using ccl specifically, I am trying to set up two sockets in the same program to serve as a fifo data structure.
to that end, I've been standing up test code to exercise my understanding of the api, and I now have a problem I can't figure out. The following code snipped sets up two sockets, one listen and one to connect to the listen, and accepts the connection on the listen socket (the accept call waits for a connection to come in before returning, which is what I want in this case), after which we write to one socket and read from the other. the code hangs and I don't know why (I assume its because the sockets aren't connecting).
The code:
(ccl:with-open-socket (lsock :local-port 8008 :connect :passive :address-family :internet)
(ccl:with-open-socket (tsock :address-family :internet :remote-port 8008 :remote-host "127.0.0.1")
(let ((stream (ccl:accept-connection lsock)))
(write "can you see?" :stream tsock)
(read stream))))
turns out the hang was on the read call, because.... I need (stream-force-output) after the write call. tested and works. Sockets also don't seem to close without explicit calls to (close for lsock, tsock and the stream... I wonder if thats a bug? different question though.
Related
If I have a tcp connection conn, how can determine whether conn.Read will block?
My understanding is that Go's Read uses non-blocking sockets and will only block if there's no data available to read (See https://stackoverflow.com/a/36117724/4447365).
But is there any way to check if the socket has no data available?
This can be done with the POSIX read function by calling it with a count argument of zero.
When programming in Go don't worry about it. Assume everything will block. Then put it in a goroutine so it runs asynchronously anyway.
The Go runtime handles all of the details.
Also, the issue here seems to be what you want to do. The issue was rejected: Go doesn't do that. Neither does C. And even if it did it isn't reliable. If you read down to the end there are suggested solutions involving the Linger TCP setting.
This question is related to a question about getting a free port in Haskell, where I included a getFreePort function that retrieved the first available port. This function works on a Windows system, but when I tried on my Linux box it fails randomly (the free port is reported as busy).
I've modified the function to try to re-bind to the free address, and it fails at random:
getFreePort :: IO Integer
getFreePort = do
sock <- socket AF_INET Stream defaultProtocol
bind sock (SockAddrInet aNY_PORT iNADDR_ANY)
port <- socketPort sock
close sock
print "Trying to rebind to the sock"
sock <- socket AF_INET Stream defaultProtocol
bind sock (SockAddrInet port 0x0100007f)
port <- socketPort sock
close sock
return (toInteger port)
I understand that there is a race condition about other process acquiring that port, but isn't this unlikely?
As a general remark, the pattern of check if a resource is available and if so take it is often an anti-pattern. Whenever you do that you run the risk that another process takes the resource after the check but before you actually acquire it yourself.
The only info you have after such a check is that the resource was not used at that particular point in time. It may or may not help you to guess the port's state in the future but the information you have is in no way binding at any later time. You cannot assume that because the resource was free at time t it will still be free at t+dt. Even if dt is very small. It's maybe a bit more likely that it will still be free when you ask fast. But that's just it - maybe a higher probability.
You should just try to acquire a resource and handle failure appropriately. The only way you can be sure a port was really free is when you just successfully opened it. Then you know it was indeed free. As soon as you close it all bets are off again.
I don't think you can ever safely check if a port is free in one process and then assume it still is free in another process. That does not make sense. It does not even make sense within the same process!
At the very least you would have to design a protocol that would go back and forth:
here's a port that was just free, try that
nope, it's taken now
ok, here's another one
nope, it's taken now
ok, here's another one
yep, got it, thanks
But that is pretty silly to begin with. The process that needs the port should just open it. When it already has the port open and not before, then it should communicate the port number to the other party.
start listening client with netcat -l
go program opens a conn with net.DialTCP to said client.
kill the netcat
in go program, do conn.Write() with a []byte -> it runs fine without error!
it takes another conn.Write to get the error: broken pipe
The first write is the one where data loss happens, and I want to avoid. if i only get an error I know i can just keep the data and try again later.
I've seen https://stackoverflow.com/a/15071574/2757887 which is a very similar case and the explanation seems to apply here, but it still doesn't explain how to deal with the issue, if the tcp protocol I need to implement only does one-way communication.
I've sniffed the traffic with wireshark, and when i kill the netcat, I can see that it sends FIN to the go program, to which the go program replies with ACK. For some reason the go program doesn't immediately reply with it's own FIN - and i'm curious why that is, it might help with my problem - but there's probably a good reason for it.
Either way, from the "connection termination" section # http://en.wikipedia.org/wiki/Transmission_Control_Protocol, I conclude that the socket is in the CLOSE_WAIT state at this point, which I also confirmed with "netstat -np", which shows the socket going from ESTABLISHED to CLOSE_WAIT after killing netstat.
Looking at wireshark, the first conn.write results in a packet with push and ack fields set, and of course my payload. this is the write that succeeds fine in go.
then the old socket that used to belong to netstat sends RST,
which makes sure that as soon as i try to write in go (2nd write) it fails.
So my question is:
A) why can't I get an error on the first write? if the socket received the FIN and is in CLOSE_WAIT why does Go let me write to the socket and tell me all is fine?
B) is there any way I can check in Go whether the socket is in CLOSE_WAIT? and if so, I could for this purpose consider it closed and not do the write.
thanks,
Dieter
Fundamentally, a successful write only tells you that data has been queued to be sent to the other end. If you need to make sure the other end gets that data, even if the connection closes or errors, you must store a copy of the data until the other end provides you with an application-level acknowledgment.
Say one part of a program writes some stuff to a socket and another part of the same program reads stuff from that same socket. If an external tool writes to that very same socket, how would I differentiate who wrote what to the socket (using the part that reads it)? Would using a named pipe work?
If you are talking about TCP the situation you describe is impossible, because connections are 1-to-1. If you mean UDP, you can get the sender address by setting the appropriate flags in the recvmesg() function.
is it possible in any common platform - say, in Windows - to write a servient process that creates a socket, binds it to exactly one local "address:port" (fixed), and then:
use it to listen for incoming connections (on the specified port)
while at the same time
use it as a client socket to connect to some other servient (having source port identical to the one it exposes to others) ?
that is (sorry for the syntax abuse):
mySocket=socket(); mySocket.bind(myaddress, 3000);
mySocket.connectTo(neighbour, whateverport); // and present to others as port 3000
mySocket.listen(); // and it listens on 3000
mySocket.accept();
?
iirc, it's not even possible/advisable to try, even in the case an API wouldn't complain, but maybe it's me that is playing too much by the book... so I thought of asking you
thanks a lot!
No, a socket cannot be used for both listening and connecting at the same time. connect() will return a WSAEINVAL error if listen() was already called, and listen() will return a WSAEISCONN error if connect() was already called. You need to use separate sockets.
And if you could, there's be all kinds of troubles that crop up. For example, if select() returns that the socket is readable, do you do a recv() or an accept()? You want 2 sockets to play those two roles.
What advantage is there in one socket? For example, if you were hoping to do a blocking read until something interesting happens (incoming connection, incoming data), there are alternatives. In that example, you'd use select() to block on two sockets at once. The result from select() tells you which socket is ready. That tells you if you want to accept() a new connection from the one socket or recv() new data from the other socket.