How do I bind an inet socket to localhost (127.0.0.1) in Standard ML? I came up with Socket.bind (socket, INetSock.toAddr (valOf (NetHostDB.fromString "127.0.0.1"), portNumber)), but this seems awfully verbose. I think there might exist a simpler way. Is there a simpler way?
For context, this is the program:
fun startServer () =
let
val socket = INetSock.TCP.socket ()
val localhost = valOf (NetHostDB.fromString "127.0.0.1")
in
Socket.bind (socket, INetSock.toAddr (localhost, 8000));
Socket.listen (socket, 10);
(* ... do some things with the socket ... *)
end
Related
I was trying to follow the ktor documentation for Raw Sockets and in specific the part related to secured sockets (https://ktor.io/servers/raw-sockets.html):
runBlocking {
val socket = aSocket(ActorSelectorManager(ioCoroutineDispatcher)).tcp().connect(InetSocketAddress("google.com", 443)).tls()
val w = socket.openWriteChannel(autoFlush = false)
w.write("GET / HTTP/1.1\r\n")
w.write("Host: google.com\r\n")
w.write("\r\n")
w.flush()
val r = socket.openReadChannel()
println(r.readUTF8Line())
}
You can adjust a few optional parameters for the TLS connection:
suspend fun Socket.tls(
trustManager: X509TrustManager? = null,
randomAlgorithm: String = "NativePRNGNonBlocking",
serverName: String? = null,
coroutineContext: CoroutineContext = ioCoroutineDispatcher
): Socket
But the NativePRNGNonBlocking SecureRandom algorithm is not available on Windows, so my only option was to use SHA1PRNG (https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SecureRandomImp)
This is the code I'm running to connect to a listening socket :
socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress(host, port))
.tls(Dispatchers.IO, randomAlgorithm = "SHA1PRNG")
Unfortunately, I always receive the same error: "Channel was closed"
If I remove tls, keeping only the raw socket:
socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress(host, port))
Everything works as expected.
Does anyone has used Ktor Secure Sockets in Windows ? (Unfortunately, Ktor's documentation still has a long way to go).
Thanks,
J
I'm trying to write a very simple Python 2.7 function to listen for a socket connection on a localhost port.
Question is: If something bad happens when is my code responsible for killing the socket so that is not left dangling out there? In what cases will a socket error close the socket for me so that I don't need to call 'close()'?
I want to avoid having to start my testing all over with a different port because the old one was left open.
Python code sample:
def getconn(PORT,TIMEOUT_SECS):
conn = ''
try:
HOST = ''
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.settimeout(TIMEOUT_SECS)
s1.bind((HOST, PORT))
s1.listen(1)
conn, addr = s1.accept()
print('Connected by', addr)
except socket.timeout as e:
conn = 'socket timeout'
except socket.error as e:
conn = 'other socket error'
except:
conn = 'deaddead'
if s1:
s1.close()
return conn
And used here (say PORT argument is 19111)...
def runtest01_normalpoll(PORT):
conn = getconn(PORT, 10.0)
if conn == 'socket timeout' or conn == 'other socket error' or conn == 'deaddead':
print 'could not establish a connection...why you ask?', conn
else:
conn.close()
print 'done...'
It seems to work but am I missing any edge cases that would leave the socket open or cause anything else bad to happen?
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)
I've been working on a client for this chat server but I am running into a bit of a challenge. The server uses Python's 3.4RC1 asyncio module.
Behavior:
My client connects. My second client connects. Either can send messages to the server BUT, the server is not broadcasting them as it should in a normal public chat room.
User1: Hello. Presses Enter.
User2 does not see it.
User2: Anyone there? Presses Enter.
User2 sees User1: Hello. and User2: Anyone there?
Just... strange. Not sure what I'm missing.
Here are the files. Give it a try.
Server:
from socket import socket, SO_REUSEADDR, SOL_SOCKET
from asyncio import Task, coroutine, get_event_loop
class Peer(object):
def __init__(self, server, sock, name):
self.loop = server.loop
self.name = name
self._sock = sock
self._server = server
Task(self._peer_handler())
def send(self, data):
return self.loop.sock_send(self._sock, data.encode('utf-8'))
#coroutine
def _peer_handler(self):
try:
yield from self._peer_loop()
except IOError:
pass
finally:
self._server.remove(self)
#coroutine
def _peer_loop(self):
while True:
buf = yield from self.loop.sock_recv(self._sock, 1024)
if buf == b'':
break
self._server.broadcast('%s: %s' % (self.name, buf.decode('utf-8')))
class Server(object):
def __init__(self, loop, port):
self.loop = loop
self._serv_sock = socket()
self._serv_sock.setblocking(0)
self._serv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self._serv_sock.bind(('',port))
self._serv_sock.listen(5)
self._peers = []
Task(self._server())
def remove(self, peer):
self._peers.remove(peer)
self.broadcast('Peer %s quit!' % (peer.name,))
def broadcast(self, message):
for peer in self._peers:
peer.send(message)
#coroutine
def _server(self):
while True:
peer_sock, peer_name = yield from self.loop.sock_accept(self._serv_sock)
peer_sock.setblocking(0)
peer = Peer(self, peer_sock, peer_name)
self._peers.append(peer)
self.broadcast('Peer %s connected!' % (peer.name,))
def main():
loop = get_event_loop()
Server(loop, 1234)
loop.run_forever()
if __name__ == '__main__':
main()
Client:
# import socket
from socket import *
# form socket import socket, bind, listen, recv, send
HOST = 'localhost' #localhost / 192.168.1.1
# LAN - 192.168.1.1
PORT = 1234
s = socket(AF_INET, SOCK_STREAM)# 98% of all socket programming will use AF_INET and SOCK_STREAM
s.connect((HOST, PORT))
while True:
message = input("Your Message: ")
encoded_msg = message.encode('utf-8')
s.send(encoded_msg)
print('Awaiting Reply..')
reply = s.recv(1024)
decoded_reply = reply.decode('utf-8')
decoded_reply = repr(decoded_reply)
print('Received ', decoded_reply)
s.close()
Here's the non threaded server code I wrote. works great but ONLY between 2 people. How could this code be updated to broadcast every message received to all clients connected?
# import socket
from socket import *
# form socket import socket, bind, listen, recv, send
HOST = 'localhost' #localhost / 192.168.1.1
# LAN - 192.168.1.1
PORT = 1234
s = socket(AF_INET, SOCK_STREAM) # 98% of all socket programming will use AF_INET and SOCK_STREAM
s.bind((HOST, PORT))
s.listen(5) # how many connections it can receive at one time
conn, addr = s.accept() # accept the connection
print('Connected by', addr) # print the address of the person connected
while True:
data = conn.recv(1024)
decoded_data = data.decode('utf-8')
data = repr(decoded_data)
print('Received ', decoded_data)
reply = input("Reply: ")
encoded_reply = reply.encode('utf-8')
conn.sendall(encoded_reply)
print('Server Started')
conn.close()
Okay, let’s think about what your client does. You ask for a message to send, blocking for user input. Then you send that message and receive whatever there is at the server. Afterwards, you block again, waiting for another message.
So when client A sends a text, client B is likely blocking for user input. As such, B won’t actually check if the server sent anything. It will only display what’s there after you have sent something.
Obviously, in a chat, you don’t want to block on user input. You want to continue receiving new messages from the server even if the user isn’t sending messages. So you need to separate those, and run both asynchronously.
I haven’t really done much with asyncio yet, so I don’t really know if this can be nicely done with it, but you essentially just need to put the reading and sending into two separate concurrent tasks, e.g. using threads or concurrent.futures.
A quick example of what you could do, using threading:
from socket import *
from threading import Thread
HOST = 'localhost'
PORT = 1234
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
def keepReading ():
try:
while True:
reply = s.recv(1024).decode()
print('Received ', reply)
except ConnectionAbortedError:
pass
t = Thread(target=keepReading)
t.start()
try:
while True:
message = input('')
s.send(message.encode())
except EOFError:
pass
finally:
s.close()
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.