IPv4 IPv6の取扱について
socketのaddress family AF_UNSPECを用いるとv4/6を同じソケットで扱えるが serverのbindにaddrinfoを用いる方法がないため、v4決め打ちのコードで実装している。
いま、思いつく方法の一つはbind4 <|> bind6みたいにMonadPlusかなんかで 両方を実行して両方が失敗したときのみ例外を捕まえるやりかた。
あとは、network packageをどうにかしないと行けないと思う。
.stack-work |
module Main where | |
import Data.List(find) | |
import qualified Network.Socket as S | |
import qualified Network.Socket.ByteString as SB | |
import qualified Data.ByteString.Char8 as C | |
import Data.Maybe | |
import Control.Monad (unless) | |
main :: IO () | |
main = S.withSocketsDo client | |
hint = S.defaultHints { S.addrSocketType = S.Datagram, S.addrProtocol = 17} | |
host = "localhost" | |
client = do | |
info <- S.getAddrInfo (Just hint) (Just host) (Just "3000") | |
let saddr = find (\ i -> S.AF_INET == S.addrFamily i ) info | |
unless ( isNothing saddr ) $ do | |
sock <- S.socket (S.addrFamily $ fromJust saddr) S.Datagram S.defaultProtocol | |
print $ S.addrAddress $ fromJust saddr | |
SB.sendTo sock | |
(C.pack "Hello, world!") | |
(S.addrAddress $ fromJust saddr) | |
msg <- SB.recv sock 1024 | |
S.close sock | |
putStr "Received " | |
C.putStrLn msg | |
IPv4 IPv6の取扱について
socketのaddress family AF_UNSPECを用いるとv4/6を同じソケットで扱えるが serverのbindにaddrinfoを用いる方法がないため、v4決め打ちのコードで実装している。
いま、思いつく方法の一つはbind4 <|> bind6みたいにMonadPlusかなんかで 両方を実行して両方が失敗したときのみ例外を捕まえるやりかた。
あとは、network packageをどうにかしないと行けないと思う。
Copyright Kouichi Nakanishi (c) 2017 | |
All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are met: | |
* Redistributions of source code must retain the above copyright | |
notice, this list of conditions and the following disclaimer. | |
* Redistributions in binary form must reproduce the above | |
copyright notice, this list of conditions and the following | |
disclaimer in the documentation and/or other materials provided | |
with the distribution. | |
* Neither the name of Kouichi Nakanishi nor the names of other | |
contributors may be used to endorse or promote products derived | |
from this software without specific prior written permission. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
{-# LANGUAGE OverloadedStrings #-} | |
module Main where | |
import qualified Control.Exception as E | |
import Network.Socket | |
import qualified Network.Socket.ByteString as B | |
import qualified Data.ByteString.Char8 as B8 | |
port = 3000 | |
maxline = 1024 | |
main :: IO () | |
main = withSocketsDo echoserver | |
echoserver :: IO () | |
echoserver = do | |
sockv4 <- socket AF_INET Datagram 0 | |
bind4 sockv4 `E.catch` (print :: E.SomeException -> IO()) | |
sockv6 <- socket AF_INET6 Datagram 0 | |
setSocketOption sockv6 IPv6Only 1 | |
bind6 sockv6 `E.catch` (print :: E.SomeException -> IO ()) | |
echo sockv4 | |
where | |
bind4 s = bind s (SockAddrInet port iNADDR_ANY) | |
bind6 s = bind s (SockAddrInet6 port 0 (0,0,0,1) 0) | |
echo :: Socket -> IO () | |
echo sock = do | |
(mesg, client) <- B.recvFrom sock maxline | |
B.sendTo sock ("resp:" `B8.append` mesg) client | |
close sock | |
import Distribution.Simple | |
main = defaultMain |
# This file was automatically generated by 'stack init' | |
# | |
# Some commonly used options have been documented as comments in this file. | |
# For advanced use and comprehensive documentation of the format, please see: | |
# http://docs.haskellstack.org/en/stable/yaml_configuration/ | |
# Resolver to choose a 'specific' stackage snapshot or a compiler version. | |
# A snapshot resolver dictates the compiler version and the set of packages | |
# to be used for project dependencies. For example: | |
# | |
# resolver: lts-3.5 | |
# resolver: nightly-2015-09-21 | |
# resolver: ghc-7.10.2 | |
# resolver: ghcjs-0.1.0_ghc-7.10.2 | |
# resolver: | |
# name: custom-snapshot | |
# location: "./custom-snapshot.yaml" | |
resolver: lts-7.16 | |
# User packages to be built. | |
# Various formats can be used as shown in the example below. | |
# | |
# packages: | |
# - some-directory | |
# - https://example.com/foo/bar/baz-0.0.2.tar.gz | |
# - location: | |
# git: https://github.com/commercialhaskell/stack.git | |
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a | |
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a | |
# extra-dep: true | |
# subdirs: | |
# - auto-update | |
# - wai | |
# | |
# A package marked 'extra-dep: true' will only be built if demanded by a | |
# non-dependency (i.e. a user package), and its test suites and benchmarks | |
# will not be run. This is useful for tweaking upstream packages. | |
packages: | |
- '.' | |
# Dependency packages to be pulled from upstream that are not in the resolver | |
# (e.g., acme-missiles-0.3) | |
extra-deps: [] | |
# Override default flag values for local packages and extra-deps | |
flags: {} | |
# Extra package databases containing global packages | |
extra-package-dbs: [] | |
# Control whether we use the GHC we find on the path | |
# system-ghc: true | |
# | |
# Require a specific version of stack, using version ranges | |
# require-stack-version: -any # Default | |
# require-stack-version: ">=1.3" | |
# | |
# Override the architecture used by stack, especially useful on Windows | |
# arch: i386 | |
# arch: x86_64 | |
# | |
# Extra directories used by stack for building | |
# extra-include-dirs: [/path/to/dir] | |
# extra-lib-dirs: [/path/to/dir] | |
# | |
# Allow a newer minor version of GHC than the snapshot specifies | |
# compiler-check: newer-minor |
name: udp-sample | |
version: 0.1.0.0 | |
synopsis: upd sample server/client by haskell | |
description: Please see README.md | |
homepage: https://github.com/keizo042/upd-sample#readme | |
license: BSD3 | |
license-file: LICENSE | |
author: Kouichi Nakanishi | |
maintainer: keizo.bookman@gmail.com | |
copyright: 2017 Kouichi Nakanishi | |
category: Web | |
build-type: Simple | |
cabal-version: >=1.10 | |
extra-source-files: DESCRIPTION.md | |
executable server | |
main-is: Server.hs | |
default-language: Haskell2010 | |
build-depends: base >= 4.7 && < 5 | |
,network | |
,conduit-extra | |
,unix | |
,bytestring | |
executable client | |
main-is: Client.hs | |
default-language: Haskell2010 | |
build-depends: base >= 4.7 && < 5 | |
,network | |
,conduit-extra | |
,unix | |
,bytestring | |