Create haskel socket client - sockets

I try to connect to created socket by haskell:
-- Logger
putStrLn "Create socket"
sock_logger <- socket AF_INET Stream 0
putStrLn "Bind socket"
connect sock_logger (SockAddrInet 5000 0)
putStrLn "Listen socket"
listen sock_logger 2
putStrLn "Logger listening on port 5000..."
(conn_logger, _) <- accept sock_logger
putStrLn "Logger connection accepted"
Scocket already created by other application. But after connect sock_logger (SockAddrInet 5000 0) i get
helloworld-exe.EXE: Network.Socket.connect: <socket: 440>: failed (Cannot assign requested address (WSAEADDRNOTAVAIL))
How can i connect to socket as client (without creation new socket)
All sockets i create with SockAddrInet 5000 0. Can it depends on addlress (maybe need 127.0.0.1 instead localhost?)

Perhaps you're looking for tupleToHostAddress, as in
connect sock_logger (SockAddrInet 5000 (tupleToHostAddress (127, 0, 0, 1)))

Thx Daniel Wagner, it's really need to use tupleToHostAddress (127, 0, 0, 1) and listen ... is wrong. Right version:
putStrLn "Create socket"
sock_logger <- socket AF_INET Stream 0
putStrLn "Bind socket"
connect sock_logger (SockAddrInet 5000 (tupleToHostAddress (127, 0, 0, 1)))
putStrLn "Connected to logger on port 5000..."

Related

Can you start a new TCP server from within a running TCP server?

I'm doing a kind of odd experiment with Elixir. (Maybe it's not odd, but I haven't done it before.)
I'm trying to set up a TCP server that can trigger other TCP servers based on some input. This isn't going into production anywhere - just trying to see what's possible. I'm not super familiar with TCP.
The first server starts fine, but my code throws this error when I try to type something like "PORT 9000" into the first server (via telnet):
FunctionClauseError) no function clause matching in :inet_tcp.getserv/1
(kernel) inet_tcp.erl:55: :inet_tcp.getserv("9000")
(kernel) gen_tcp.erl:190: :gen_tcp.listen/2
(gen_tcp) lib/tcp_server.ex:11: TcpServer.init/1
(stdlib) gen_server.erl:328: :gen_server.init_it/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Here is the code:
defmodule TcpServer do
use GenServer
def start_link(port) do
ip = Application.get_env :tcp_server, :ip, {127,0,0,1}
port = Application.get_env :tcp_server, :port, port
GenServer.start_link(__MODULE__,[ip,port],[])
end
def init [ip,port] do
{:ok, listen_socket} = :gen_tcp.listen(port,[:binary, {:packet, 0}, {:active, true}, {:ip, ip}])
{:ok, socket} = :gen_tcp.accept listen_socket
{:ok, %{ip: ip, port: port, socket: socket}}
end
def handle_info({ :tcp, socket, packet }, state) do
# Expects something like "PORT 3456"
if packet =~ "PORT" do
port_number = String.slice(packet, -5..-2)
TcpServer.start_link(port_number)
:gen_tcp.send socket, "Started new server on port #{port_number}"
else
:gen_tcp.send socket, "Message received... \n"
end
IO.inspect packet, label: "incoming packet"
{:noreply, state}
end
def handle_info({:tcp_closed, socket}, state) do
IO.inspect "Socket has been closed"
{:noreply, state}
end
def handle_info({:tcp_error, socket, reason}, state) do
IO.inspect socket,label: "connection closed dut to #{reason}"
{:noreply, state}
end
end
Am I doing something wrong, or will this just not work for some reason that I'm not aware of?
(Code mostly pulled from https://medium.com/blackode/quick-easy-tcp-genserver-with-elixir-and-erlang-10189b25e221)
Found this in the Erlang docs:
getserv(Port) when is_integer(Port) -> {ok, Port};
Looks like I needed this:
{port_number, _extra} = Integer.parse(String.slice(packet, -5..-2))
You should convert port_number to integer before passing to any inet functions.
I recommend to use SockErl

Qpython, socket connection error

I'm learning server- and client-side connections:
What I'm attempting to do is connecting server- and client-side scripts with each other on Qpython(android)
The problem is when I run it, it gives me this:
"ConnectionRefusedError: Errno [111] Connection Refused"
When I run the same scripts on my computer it gives me no error.
Background information:
I'm using 2 different apps on my phone
And 1 on my computer.
But I suppose that can't be the problem
Client
import socket
import sys
HOST, PORT = "localhost", 9999
Data = " ".join(sys.argv[1:]) + input(" Enter Message:\n"
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(bytes(data + "\n", "utf-8"))
# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
finally:
sock.close()
print("Sent: {}".format(data))
print("Received: {}".format(received))
Server
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()

Destination Unreachable (Port Unreachable) using Haskell

Using Wireshark to debug, I receive the following error when sending UDP packets on localhost:
Destination Unreachable (Port Unreachable)
Checksum: 0x0000 (Illegal)
I am constructing my server first on a port between 10000 - 15000 using
startServer :: Port -> IO Server
startServer port = withSocketsDo $ do
-- Look up the server address and port information.
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
-- Bind to the socket.
sock <- socket (addrFamily serverAddress) Datagram defaultProtocol
bindSocket sock (addrAddress serverAddress)
-- Create the server and run the client send and receive threads.
clients <- newMVar $ createEmptyClients
let server = Server sock port clients
_ <- forkIO $ forever $ receiveClientJoin server
return server
I am listening for new clients connecting via UDP using
-- | Connected a client to the server.
receiveClientJoin :: Server -> IO ()
receiveClientJoin server = do
print "Receiving"
(msg, _, clSockAddr) <- recvFrom (sSocket server) 4096
print $ "Server received client join message: " ++ msg
And I am connecting to the server with clients using
connectToServer port = do
-- Get the server's address and port information.
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
sock <- socket (addrFamily serverAddr) Datagram defaultProtocol
sendTo sock "Hello from this client!" (addrAddress serverAddr)
Why are my clients' packets not finding the server?
The problem is you are listening on an IPv6 address and trying to connect to an IPv4 address. This is actually a slightly common problem. For example, I ran across this issue when working with commsec.
Consider the fragments where you discover your AddrInfo:
import Network.Socket
main :: IO ()
main = do
let port = "2474"
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
print serverAddress
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
print serverAddr
Now the output will vary by machine, but on one of my CentOS systems with both IPv4 and IPv6 addresses the output clearly shows the second (connect) address is IPv6 while the first (listen) address is IPv4:
AddrInfo {addrFlags = [AI_PASSIVE], addrFamily = AF_INET, addrSocketType = Stream, addrProtocol = 6, addrAddress = 0.0.0.0:2474, addrCanonName = Nothing}
AddrInfo {addrFlags = [AI_ADDRCONFIG,AI_V4MAPPED], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [::1]:2474, addrCanonName = Nothing}
One solution is to force a particular version of IP via a hint or an address (ex. an IPv4 address as in my comment). The hint solution is probably more desirable:
-- For servers:
addrs <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6
, addrFlags = [AI_PASSIVE] })
Nothing (Just port)
-- For clients:
addrInfo <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6 })
(Just "localhost") (Just port)

Use of IN6ADDR_SETV4MAPPED and dual stack sockets

This is a continuation of Connecting IPv4 client to IPv6 server: connection refused. I am experimenting with dual stack sockets and trying to understand what setsockopt with IPV6_V6ONLY is useful for. On the linked question I was advised that "Setting IPV6_V6ONLY to 0 can be useful if you also bind the server to an IPv6-mapped IPv4 address". I have done this below, and was expecting my server to be able to accept connections from both an IPv6 and an IPv4 client. But shockingly when I run my client with a V4 and a V6 socket, neither can connect!
Can someone please tell me what I am doing wrong, or have I misunderstood IPv6 dual stack functionality all together?
Server:
void ConvertToV4MappedAddressIfNeeded(PSOCKADDR pAddr)
{
// if v4 address, convert to v4 mapped v6 address
if (AF_INET == pAddr->sa_family)
{
IN_ADDR In4addr;
SCOPE_ID scope = INETADDR_SCOPE_ID(pAddr);
USHORT port = INETADDR_PORT(pAddr);
In4addr = *(IN_ADDR*)INETADDR_ADDRESS(pAddr);
ZeroMemory(pAddr, sizeof(SOCKADDR_STORAGE));
IN6ADDR_SETV4MAPPED(
(PSOCKADDR_IN6)pAddr,
&In4addr,
scope,
port
);
}
}
addrinfo* result, hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int nRet = getaddrinfo("powerhouse", "82", &hints, &result);
SOCKET sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
int no = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) != 0)
return -1;
ConvertToV4MappedAddressIfNeeded(result->ai_addr);
if (bind(sock, result->ai_addr, 28/*result->ai_addrlen*/) == SOCKET_ERROR)
return -1;
if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
return -1;
SOCKET sockClient = accept(sock, NULL, NULL);
printf("Got one!\n");
Client:
addrinfo* result, *pCurrent, hints;
char szIPAddress[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
const char* pszPort = "82";
if (getaddrinfo("powerhouse", "82", &hints, &result) != 0)
return -1;
SOCKET sock = socket(AF_INET, result->ai_socktype, result->ai_protocol);
int nRet = connect(sock, result->ai_addr, result->ai_addrlen);
My C skills are a bit rusty, so here is a counter-example written in Python. My local IPv4 address is 37.77.56.75, so that is what I will bind to. I kept it as simple as possible to focus on the concepts.
This is the server side:
#!/usr/bin/env python
import socket
# We bind to an IPv6 address, which contains an IPv6-mapped-IPv4-address,
# port 5000 and we leave the flowinfo (an ID that identifies a flow, not used
# a lot) and the scope-id (basically the interface, necessary if using
# link-local addresses)
host = '::ffff:37.77.56.75'
port = 5000
flowinfo = 0
scopeid = 0
sockaddr = (host, port, flowinfo, scopeid)
# Create an IPv6 socket, set IPV6_V6ONLY=0 and bind to the mapped address
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(sockaddr)
# Listen and accept a connection
sock.listen(0)
conn = sock.accept()
# Print the remote address
print conn[1]
Here we bind to an IPv6 address in the code, but the address is actually an IPv6-mapped IPv4 address, so in reality we are binding to an IPv4 address. This can be seen when looking at i.e. netstat:
$ netstat -an | fgrep 5000
tcp4 0 0 37.77.56.75.5000 *.* LISTEN
We can then use an IPv4 client to connect to this server:
#!/usr/bin/env python
import socket
# Connect to an IPv4 address on port 5000
host = '37.77.56.75'
port = 5000
sockaddr = (host, port)
# Create an IPv4 socket and connect
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
conn = sock.connect(sockaddr)
And the server will show us who connected, using IPv6 address representation:
('::ffff:37.77.56.76', 50887, 0, 0)
In this example I connected from IPv4 host 37.77.56.76, and it choose port 50887 to connect from.
In this example we are only listening on an IPv4 address (using IPv6 sockets, but it is still an IPv4 address) so IPv6-only clients will not be able to connect. A client with both IPv4 and IPv6 could of course use IPv6 sockets with IPv6-mapped-IPv4-addresses, but then it would not really be using IPv6, just an IPv6 representation of an IPv4 connection.
A dual-stack server has to either:
listen on the wildcard address, which will make the OS accept connections on any address (both IPv4 and IPv6)
listen on both an IPv6 address and an IPv4 address (either by creating an IPv4 socket, or by creating an IPv6 socket and listening to an IPv6-mapped-IPv4-address as shown above)
Using the wildcard address is the most simple. Just use the server example from above and replace the hostname:
# We bind to the wildcard IPv6 address, which will make the OS listen on both
# IPv4 and IPv6
host = '::'
port = 5000
flowinfo = 0
scopeid = 0
sockaddr = (host, port, flowinfo, scopeid)
My Mac OS X box shows this as:
$ netstat -an | fgrep 5000
tcp46 0 0 *.5000 *.* LISTEN
Notice the tcp46 which indicates that it listens on both address families. Unfortunately on Linux it only shows tcp6, even when listening on both families.
Now for the most complicated example: listening on multiple sockets.
#!/usr/bin/env python
import select
import socket
# We bind to an IPv6 address, which contains an IPv6-mapped-IPv4-address
sockaddr1 = ('::ffff:37.77.56.75', 5001, 0, 0)
sock1 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
sock1.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock1.bind(sockaddr1)
sock1.listen(0)
# And we bind to a real IPv6 address
sockaddr2 = ('2a00:8640:1::224:36ff:feef:1d89', 5001, 0, 0)
sock2 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
sock2.bind(sockaddr2)
sock2.listen(0)
# Select sockets that become active
sockets = [sock1, sock2]
readable, writable, exceptional = select.select(sockets, [], sockets)
for sock in readable:
# Accept the connection
conn = sock.accept()
# Print the remote address
print conn[1]
When running this example both sockets are visible:
$ netstat -an | fgrep 5000
tcp6 0 0 2a00:8640:1::224.5000 *.* LISTEN
tcp4 0 0 37.77.56.75.5000 *.* LISTEN
And now IPv6-only clients can connect to 2a00:8640:1::224:36ff:feef:1d89 and IPv4-only clients can connect to 37.77.56.75. Dual stack clients can choose which protocol they want to use.

Cannot connect to socket on local machine

I did a simple translation of the example C# code here:
let socket_CreateBindListen (sv_ : string) (pt_ : int) : Socket option =
let (he : IPHostEntry) = Dns.GetHostEntry(sv_)
let rsock, ipe =
he.AddressList
|> Seq.map (fun s ->
let (ipe2 : IPEndPoint) = new IPEndPoint (s, pt_)
let (rsock2 : Socket) = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
rsock2.Connect ipe2 ///// <---- No connection could be made because the target machine actively refused it
rsock2, ipe2)
|> Seq.find (fun (s, t) -> s.Connected)
try
rsock.Bind ipe
rsock.Listen 10
printfn "%s now listening on port %d" sv_ pt_
Some (rsock)
with
| _ ->
printfn "Failed to connect to %s on port %d" sv_ pt_
None
socket_CreateBindListen "127.0.0.1" 50000
I made sure to first open port 50000 on my machine for TCP for both inbound and outbound connections. (I even tried disabling the firewall completely.) Nothing seems to be working. I keep getting the error message:
No connection could be made because the target machine actively refused it.
I am using Windows 8. I would really appreciate some pointers on what else I might try.
Thanks in advance for your time.
EDIT
I hope I am not violating any of StackOverflow's posting policies by blogging about my progress here.
I have updated the code to the following:
let socket_CreateBindListen (sv_ : string) (pt_ : int) : Socket option =
let (he : IPHostEntry) = Dns.GetHostEntry(sv_)
let rsock, ipe =
he.AddressList
|> Seq.map (fun s ->
let (ipe2 : IPEndPoint) = new IPEndPoint (s, pt_)
let (rsock2 : Socket) = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
try
rsock2.Connect ipe2
rsock2, ipe2
with
| _ ->
null, null)
|> Seq.find (fun (s, t) -> (s <> null) && (s.Connected))
try
rsock.Bind ipe
rsock.Listen sbl
printfn "%s now listening on port %d" sv_ pt_
Some (rsock)
with
| _ ->
printfn "Failed to connect to %s on port %d" sv_ pt_
None
Now I am getting the following error:
KeyNotFoundException was unhandled
An unhandled exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in FSharp.Core.dll
I have looked extensively on Google and Bing, without any luck.
EDIT 2
As requested by Jack P., here is the output from netstat -a, as well as what happens when the binary is executed:
PS C:\Users\shredderroy> netstat -a
Active Connections
Proto Local Address Foreign Address State
TCP 0.0.0.0:80 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:135 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:445 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:2179 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:49152 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:49153 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:49154 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:49155 SPEEDMACHINE:0 LISTENING
TCP 0.0.0.0:49156 SPEEDMACHINE:0 LISTENING
TCP 192.168.0.139:139 SPEEDMACHINE:0 LISTENING
TCP 192.168.0.139:49159 bn1wns2011708:https ESTABLISHED
TCP 192.168.0.139:49167 vc-in-f108:imaps ESTABLISHED
TCP 192.168.0.139:49171 vc-in-f108:imaps ESTABLISHED
TCP 192.168.0.139:49239 a23-67-250-112:http CLOSE_WAIT
TCP [::]:80 SPEEDMACHINE:0 LISTENING
TCP [::]:135 SPEEDMACHINE:0 LISTENING
TCP [::]:445 SPEEDMACHINE:0 LISTENING
TCP [::]:2179 SPEEDMACHINE:0 LISTENING
TCP [::]:49152 SPEEDMACHINE:0 LISTENING
TCP [::]:49153 SPEEDMACHINE:0 LISTENING
TCP [::]:49154 SPEEDMACHINE:0 LISTENING
TCP [::]:49155 SPEEDMACHINE:0 LISTENING
TCP [::]:49156 SPEEDMACHINE:0 LISTENING
UDP 0.0.0.0:500 *:*
UDP 0.0.0.0:4500 *:*
UDP 0.0.0.0:5355 *:*
UDP 127.0.0.1:53194 *:*
UDP 127.0.0.1:60316 *:*
UDP 127.0.0.1:61644 *:*
UDP 192.168.0.139:137 *:*
UDP 192.168.0.139:138 *:*
UDP [::]:500 *:*
UDP [::]:4500 *:*
UDP [::]:5355 *:*
UDP [fe80::b193:4f6:d053:6324%20]:546 *:*
PS C:\Users\shredderroy> cd "C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug
"
PS C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug> .\SocketTests_Server.exe
Unhandled Exception: System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it [::1]:50000
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
at SocketTests_Server.TestModule_1.heo#22.Invoke(IPAddress s) in C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\TestModule_1.fs:line 25 at Microsoft.FSharp.Collections.SeqModule.TryFind[T](FSharpFunc`2 predicate, IEnumerable`1 source)
at SocketTests_Server.TestModule_1.socket_CreateBindListen_1(String sv_, Int32 pt_) in C:\Users\shredderroy\Documents\Visual Studio
2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\TestModule_1.fs:line 20
at SocketTests_Server.Program.Main(String[] args) in C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\Program.fs:line 9
PS C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug>
I am going to keep trying. So far I have added my programme, SocketTests_Server.exe, to the list of allowed programmes in Windows Firewall, opened the relevant port for inbound and outbound connections, disabled the firewall completely--all to no avail.
I think what is happening is that you are connecting twice, one of the addresses connects fine. Your code then keeps looking through the remaining addresses and tries to connect again.
Your code is lacking the equivalent of break in the C# code.
Some possible solutions:
use a while loop instead of Seq.map
Use a reference variable inside the map
Compress all the code into Seq.find and remove the call to map (probably the most elegant)
I translated the code from the page you linked -- it compiles, though I haven't tried running it.
open System
open System.Text
open System.Net
open System.Net.Sockets
let connectSocket (server : string, port : int) : Socket option =
// Get host related information.
let hostEntry = Dns.GetHostEntry server
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
hostEntry.AddressList
|> Seq.tryPick (fun address ->
let ipe2 = IPEndPoint (address, port)
let rsock2 = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
rsock2.Connect ipe2
if rsock2.Connected then
Some rsock2
else None)
// This method requests the home page content for the specified server.
let socketSendReceive (server : string, port : int) : string =
let request =
sprintf "GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n" server
let bytesSent =
Encoding.ASCII.GetBytes request
let bytesReceived = Array.zeroCreate 256
// Create a socket connection with the specified server and port.
match connectSocket (server, port) with
| None ->
"Connection failed"
| Some s ->
// Send request to the server.
s.Send (bytesSent, Array.length bytesSent, SocketFlags.None)
|> ignore
// Receive the server home page content.
let mutable bytes = 0
let mutable page =
sprintf "Default HTML page on %s:\r\n" server
// The following will block until the page is transmitted.
while bytes > 0 do
bytes <- s.Receive (bytesReceived, Array.length bytesReceived, SocketFlags.None)
page <- page + Encoding.ASCII.GetString (bytesReceived, 0, bytes)
page
//
let main args =
let port = 80
let host =
if Array.isEmpty args then
// If no server name is passed as argument to this program,
// use the current host name as the default.
Dns.GetHostName ()
else
args.[0]
socketSendReceive (host, port)
|> Console.WriteLine
EDIT: I did a little digging, and "actively refused" is the key to that error message, according to: No connection could be made because the target machine actively refused it. In short, double-check that the server you're trying to connect to is set up properly; when the connection is actively refused, there's no firewall problem -- the server is actually rejecting your connection.
If you're absolutely certain the server is set up correctly, there's one last thing you could try. According to Socket Connection Is Actively Refused (MSDN Forums), you may need to use the IPAddress.NetworkToHostOrder Method to set the port value correctly for the IPEndPoint. In that case, just add this as the first line in my connectSocket function (above):
let port = IPAddress.NetworkToHostOrder port
EDIT 2: Looking at the netstat information you posted -- there's no server LISTENING on port 50000. If you're sure the server software is set up correctly, make sure it's using the port you want (and not just choosing a random port).
First, I would like to thank everyone, in particular, #Jack P. and #John Palmer, for reading my code and offering very good and instructive suggestions. Your guidance is greatly appreciated.
I have circumvented the problem described above by using the TcpListener and TcpClient classes instead. So I thought I would write the simple F# translations of this server function and this client function, which together implement the server and client. Hopefully, this sample code will save other beginners some time.
Server
let connectAndListen () : unit =
let (laddr : IPAddress) = IPAddress.Parse ("127.0.0.1")
let lpt = 32000
let (svr : TcpListener) = new TcpListener (laddr, lpt)
try
svr.Start ()
let (bta : byte[]) = Array.create 256 (byte (0))
while true do
printfn "Waiting for a connection..."
let (cl : TcpClient) = svr.AcceptTcpClient ()
printfn "Connected"
let (ns : NetworkStream) = cl.GetStream ()
let mutable (i : int) = ns.Read (bta, 0, (Array.length bta))
while i <> 0 do
let (dat : string) = System.Text.Encoding.ASCII.GetString (bta, 0, i)
printfn "Received: %s" dat
let (msg : byte[]) = System.Text.Encoding.ASCII.GetBytes (dat.ToUpper ())
ns.Write (msg, 0, (Array.length msg))
printfn "Sent: %s" (dat.ToUpper ())
i <- ns.Read (bta, 0, (Array.length bta))
cl.Close ()
with
| excp ->
printfn "%s" excp.Message
svr.Stop ()
Client
let connect (sv_ : string) (pt_ : int) (msg_ : string) : unit =
try
let cl = new TcpClient (sv_, pt_)
let (dat : byte[]) = System.Text.Encoding.ASCII.GetBytes msg_
let (st : NetworkStream) = cl.GetStream ()
st.Write (dat, 0, (Array.length dat))
printfn "Sent: %s" msg_
let (rdat : byte[]) = Array.create 256 (byte (0))
let (i : int) = st.Read (rdat, 0, (Array.length rdat))
let (rsp : string) = System.Text.Encoding.ASCII.GetString (rdat, 0, i)
printfn "Received: %s" rsp
st.Close ()
st.Dispose ()
with
| :? ArgumentNullException as excp ->
printfn "ArgumentNullException encountered: %s" excp.Message
| :? SocketException as excp ->
printfn "SocketException encountered: %s" excp.Message
printfn "Press ENTER to continue"
Console.ReadLine () |> ignore
Place the code in separate projects, compile and run them. They work on my machine.