Problem:
Call to send(), returns Winsock Error 10038 against socket handle
Illustration:
acceptedSocket = accept (server, (sockaddr *)&sin, &len);
accept(), returns 0
A new thread, is created for each connection
send(), (in thread function) returns 10038
Illustration: - in thread function
//omitted
SOCKET RemoteSocket = (SOCKET) client;
//omitted
send (RemoteSocket, stringToSpend, strlen(stringToSpend), 0)
Suggestions:
Possible, race condition?
Could use I/O completion ports, but not at this stage
Isn't the problem in the line
acceptedSocket = accept (server, (sockaddr *)&sin, &len) == INVALID_SOCKET)
You make acceptedSocket the result of the comparison, but you should store the actual socket returned from accept somehow:
acceptedSocket = accept (server, (sockaddr *)&sin, &len);
isOK= acceptedSocket!=INVALID_SOCKET;
Although I'm a bit confused by the unbalanced parentheses in your post, so I may be wrong
accept() returns you a handle to a new connection-specific socket. for server code it's 2+ sockets involved: one is in listen state you are calling accept() for and second is one returned from accept() - it's an incoming connection socket. Following accept() can return socket for second incoming connection etc. if accept() returns 0 it's not an incoming connection - it's an error.
Hmm, seems like your send is executing too fast before the accept happened. So the socket used in send is not valid at the point send is executed. One of the obnoxious feature of multithreading. You need to wait for an event at the send thread and fire an event when an accept occurs
Related
Given the following pseudocode...
int sock = socket( AF_INET, SOCK_STREAM, 0 );
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = 0;
si.sin_addr.s_addr = htonl( inet_network( "127.0.0.100" ) );
bind( sock, (sockaddr*)&si, sizeof si );
...
struct sockaddr_in peer_addr;
inet_pton(AF_INET, "127.0.0.200", &peer_addr.sin_addr);
peer_addr.sin_family = AF_INET;
peer_addr.sin_port = htons( 9000 );
connect( sock, (sockaddr*)&peer_addr, sizeof peer_addr) );
...assuming the connect() is successful, and is followed by the peer closing its respective sockets used with listen() and returned by accept(), is it possible to reuse sock as the argument to a subsequenet connect() with a different peer address?
Experimentally, the answer seems to be "no": although the second connect() returns 0, the second peer to which I try to connect never returns from accept(). Can a knowledgeable answerer explain the nature of what is going wrong here? The 0 return value supposedly indicates success, so why might the peer accept() never unblock?
Is there something I can do to reuse sock to connect to a second peer? Or must that second connect() be done with a socket freshly-created by socket()? (I have verified that doing so works)
What is minimal work needed to reconnect existing socket to new server?
Infinite. It is impossible.
is it possible to reuse sock as the argument to a subsequenet connect() with a different peer address?
No. You cannot reconnect a TCP socket once you have called connect(), even if it failed. You have to close it and create a new socket. One reason is that if the socket wasn't bound, connect() binds it, and that binding is chosen based on the IP route to the destination, which may not be the same for the second destination.
although the second connect() returns 0
Hard to believe. Are you sure?
the second peer to which I try to connect never returns from listen().
listen() doesn't block. Do you mean accept()?
Can a knowledgeable answerer explain the nature of what is going wrong here?
Again you must mean accept(), and again it is hard to believe in the second connect() returning zero. connect() should have returned -1 with errno == EISCONN (or WSAGetLastError() == WSAEISCONN on Windows).
EDIT However calling connect() for a second time on a non-blocking socket is used to detect whether the first connect() has completed. This technique is in all the old books, but now that we have SO_ERROR the correct technique is to check getsockopt(SO_ERROR) if you got EAGAIN/EWOULBLOCK from the first connect(). You do these checks when you get a write notification from select(), or a write or error notification from (e)poll(). So all that happened in your case was that the second connect() confirmed the success of the first connect(), and ignored the different target address/port.
The 0 return value supposedly indicates success, so why might the peer listen() never unblock?
Whatever the appearance, the second connect() failed, so there was no reason for the server to do anything, let alone return from accept().
Is there something I can do to reuse sock to connect to a second peer?
No.
Or must that second connect() be done with a socket freshly-created by socket()?
Yes.
is it possible to reuse sock as the argument to a subsequenet connect() with a different peer address?
For a TCP socket, no it is not possible (for a UDP socket, it is allowed). Once a TCP socket has been closed, it cannot be reused. You need a separate socket() call for each connect() call.
HOWEVER, on Windows only, a SOCKET (from socket() or WSASocket()) can be reused, but only if it is closed using DisconnectEx() with the dwFlags parameter set to TF_REUSE_SOCKET. Then the SOCKET can be passed to ConnectEx() (or AcceptEx()).
Sorry for improper description of my question.
What my program do is that connect a server, send some data and close connection. I simplified my code as below:
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(s, (const sockaddr*)&dstAddr, sizeof(dstAddr));
send(s, (const char*)pBuffer, fileLen, 0);
shutdown(s, SD_SEND);
closesocket(s);
WSACleanup();
Only partial data was received by server before found a RST causing communication shutdown.
I wrote a simulate server program to accept connection and receive data, but the simulator could get all data. Because I couldn't access server's source code, I didn't know if something made wrong in it. Is there a way I can avoid this error by adding some code in client, or can I prove that there is something wrong in server program?
Setting socket's linger option can fix the bug. But I need to give a magic number for the value of linger time.
linger l;
l.l_onoff = 1;
l.l_linger = 30;
setsockopt(socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l));
WSASend returns before sending data to device actually
Correct.
I created a non-blocking socket and tried to send data to server.
WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)
No you didn't. You created an overlapped I/O socket.
After executed, returnValue was SOCKET_ERROR and WSAGetLastError() returned WSA_IO_PENDING. Then I called WSAWaitForMultipleEvents to wait for event being set. After it returned WSA_WAIT_EVENT_0, I called WSAGetOverlappedResult to get actual sent data length and it is the same value with I sent.
So all the data got transferred into the socket send buffer.
I called WSASocket first, then WSASend/WSAWaitForMultipleEvents/WSAGetOverlappedResult several times to send a bunch of data, and closesocket at the end.
So at the end of that process all the data and the close had been transferred to the socket send buffer.
But server couldn't receive all data, I used Wireshark to view tcp packets and found that client sent RST before all packet were sent out.
That could be for a number of reasons none of which is determinable without seeing some code.
If I slept 1 minute before calling closesocket, then server would receive all data.
Again this would depend on what else had happened in your code.
It seemed like that WSASend/WSAWaitForMultipleEvents/WSAGetOverlappedResult returned before sending data to server actually.
Correct.
The data were saved in buffer and waiting for being sent out.
Correct.
When I called closesocket, communication was shut down.
Correct.
They didn't work as my expectation.
So your expectation was wrong.
What did I go wrong? This problem only occurred in specific PCs, the application run well in others.
Impossible to answer without seeing some code. The usual reason for issuing an RST is that the peer had written data to a connection that you had already closed: in other words, an application protocol error; but there are other possibilities.
I am currently trying some new libraries (IOCP) for socket programming. And I've stumbled upon the AcceptEx functionality to enable async connections.
As the documentation says:
The AcceptEx function uses overlapped I/O, unlike the accept function. If your application uses AcceptEx, it can service a large number of clients with a relatively small number of threads. As with all overlapped Windows functions, either Windows events or completion ports can be used as a completion notification mechanism.
But I am not receving any completion when a client connects. I do however get a completion when the client sends data..
This is my code:
DWORD dwBytes;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
int iResult = WSAIoctl(m_hSocket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx, sizeof (GuidAcceptEx),
&m_lpfnAcceptEx, sizeof (m_lpfnAcceptEx),
&dwBytes, NULL, NULL);
if (iResult == SOCKET_ERROR)
{
CloseSocket();
}
And then:
WSAOVERLAPPED olOverlap;
memset(&olOverlap, 0, sizeof (olOverlap));
char lpOutputBuf[1024];
int outBufLen = 1024;
DWORD dwBytes;
BOOL bRet = m_lpfnAcceptEx( m_hSocket, hSocket, lpOutputBuf,
outBufLen - ((sizeof (sockaddr_in) + 16) * 2),
sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16,
&dwBytes, &olOverlap);
if ( bRet == FALSE )
{
DWORD dwRet = WSAGetLastError();
if( dwRet != WSA_IO_PENDING )
{
return dwRet;
}
}
Any suggestion of what to do to receive completions?
EDIT:
I bind the hSocket to the completionport after m_lpfnAcceptEx()
Firstly the WSAOVERLAPPED and data buffer that you're declaring on the stack above your call to AcceptEx() will not be in existence when a completion occurs (unless you are calling GetQueuedCompletionStatus() in the same function, which would be a trifle odd). You need to dynamically allocate them or pool them.
Secondly you state that you associate the socket to the completion port after you call AcceptEx(). That's wrong. You need to do these things before you call AcceptEx().
Create a socket with WSA_FLAG_OVERLAPPED set.
Bind it to the address you want to listen on.
Call listen on it with your desired backlog.
Load AcceptEx() dynamically using the listening socket and a call to WSAIoctl (not strictly necessary and the code you show should work but this way you can be sure you get your listening socket from the same underlying winsock provider and that it supports AcceptEx().
Load GetAcceptExSockaddrs() in the same way as you load AcceptEx() - you'll need it once the accept completes.
Associate the listening socket to your IOCP.
Now you can post a number of AcceptEx() calls using the listening socket and new 'accept' socket which you create like this:
Create a socket with WSA_FLAG_OVERLAPPED set.
Associate the socket to your IOCP.
As stated above you need to ensure that the buffer and the OVERLAPPED are unique per call and last until the completion occurs.
When the completion occurs you have to do the following....
Call setsockopt() with SO_UPDATE_ACCEPT_CONTEXT on the accepted socket using the listening socket as the data...
Deblock your addresses using GetAcceptExSockaddrs().
Process any data (if you allocated enough space in the buffer for data).
Note that by design AcceptEx() can be used to accept a new connection and return the initial data from that connection in one operation (this leads to slightly better performance in situations where you know you will always want some data before you can start doing things but is horribly complex to manage if you want to defend aginst the denial of service attack that can be launched simply by connecting and NOT sending data - I wrote about this here).
If you do not want AcceptEx() to wait for data to arrive then simply provide a data buffer that is ONLY big enough for the addresses to be returned and pass 0 as the 'buffer size'. This will cause the AcceptEx() to operate like an overlaped accept() and return as soon as the connection is established.
Note that Martin James' initial comment to your question is in fact the answer you're looking for. Don't pass outBufLen - ((sizeof (sockaddr_in) + 16) * 2), pass 0.
I am very new to networking and have an issue with sending messages during a while loop.
To my knowledge I should do something along the lines of this:
Create Socket()
Connect()
While
Do logic
Send()
End while
Close Socket()
However it sends once and returns -1 there after.
The code will only work when I create the socket in the loop.
While
Create Socket()
Connect()
Do logic
Send()
Close Socket()
End while
Here is a section of the code I am using but doesn't work:
//init winsock
WSAStartup(MAKEWORD(2, 0), &wsaData);
//open socket
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//connect
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(ipaddress);
serveraddr.sin_port = htons((unsigned short) port);
connect(sock, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
while(true) {
if (send(sock, request.c_str(), request.length(), 0)< 0 /*!= request.length()*/) {
OutputDebugString(TEXT("Failed to send."));
} else {
OutputDebugString(TEXT("Activity sent."));
}
Sleep(30000);
}
//disconnect
closesocket(sock);
//cleanup
WSACleanup();
The function CheckForLastError() returns:10053
WSAECONNABORTED
Software caused connection abort.
An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error
Thanks
I have been looking for a solution to this problem too. I am having the same problem with my server. When trying to send a response from inside the loop, the client seems never to receive it.
As I understand the problem, according to user207421's suggestions, when you establish a connection between a client and a server, the protocol should have enough information to let the client know when the server has finished sending the response. If you see this example, you have a minimum HTTP server that responds to requests. In this case, you can use a browser or an application like Postman. And if you see the response message, you will see a header called Connection. Setting its value to close tells the client which one is the last message from the server for that request. The message is being sent, but the client keeps waiting, maybe because there is no closing element the client can recognize. I was also missing the Content-Length header. My HTTP response message was wrong, and the client was lost.
This diagram shows what needs to be outside the loop and what needs to be inside.
To understand how and why your program fails,you have to understand the functions you use.
Some of them are blocking functions and some are them not. Some of them need previous calles of other functions and some of them don't.
Now from what i understand we are talking about a client here,not a server.
The client has only non blocking functions in this case. That means that whenever you call a function,it will be executed without waiting.
So send() will send data the second it is called and the stream will go on to the next line of code.
If the information to be sent was not yet ready...you will have a problem,since nothing will be sent.
To solve it you could use some sort of a delay. The problem with delays is that they are Blocking functions meaning your stream will stop once it hits the delay. To solve it you can create a thread and lock it untill the information is ready to be sent.
But that would do the job for one send(). You will send the info and thats that.
If you want to hold the communication and send repeatedly info,you will need to create a while loop. once you have a while loop you dont have to worry about anything. That is because you can verify that the information is ready with a stream control and you can use send over and over again before terminating the connection.
Now the question is what is happening on the server side of things?
"ipaddress" should hold the ip of the server. The server might reject your request to connect.Or worst he might accept your request but he is listening with diffrent settings in relation to your client.Meaning that maybe the server is not reciving (does not have recv() function)information and you are trying to send info... that might resault in errors/crashes and what not.
I am trying to make a c++ program work which is written by somebody else. I am having hard time understanding it. I am not even %100 sure that we can use poll() with a UDP socket but the code I am refactoring, is using poll() to read from udp socket as follows:
fd.fd = m_bsocket;
fd.events = POLLIN;
iPollResult = poll(&fd, 1, iTimeout);
if(iPollResult > 0)
{
int iReceivedByteCount = recv(m_bsocket, p_pBuffer, p_iBufferSize, 0);
if(iReceivedByteCount > 0)
{
*p_pReadSize = iReceivedByteCount;
}
else
{
eReturnValue = UDP_READ_ERROR;
}
}
return eReturnValue;
I tried sending udp packets to this program using command line:
echo "123" | nc -u 127.0.0.1 25
It looks like poll() always times out and returns 0, therefore I can not read anything.
I also wrote a small c# program that sends udp datagram, but I can not receive the message. I am wondering what I am doing wrong...
While UDP sockets can be used to connect to another host, they are mostly used "connectionless". Reading your question and comments it makes no sense that you have a connected socket. Instead it should be connectionless as suggested by WouterH in his comment.
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_port = htons(25);
sin.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr *) &sin, sizeof(sin));
// Make socket non-blocking if needed
With the above code, whenever someone sends UDP packets to port 25 on any address of your host, your socket will intercept it. Use e.g. poll or select to know when data is available.
You don't need to call connect() as UDP is connectionless. You need to bind() the socket to the IP of the interface you are listening on or 0.0.0.0 (INADDR_ANY) for all interfaces. And when sending to a destination, use sendto().
For completeness: if you call connect() on a UDP socket, you are just setting a default destination for the send() function (then you can use send instead of sendto).
If you want to receive data, you always have to bind() the socket to the interface, or all interfaces. Beware that you will have to verify the source address from the messages you are receiving. So you might want to filter the sender by using recvfrom() and checking the source address.