Click here to Skip to main content
15,886,857 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello guys.
I have created a server application that many clients connect to it. every connection has a thread, no thread pooling. The admin at a client, say client A, wants to disconnect client B.
Currently, I disconnect client B by closing the socket of thread B, which is associated to client B.
C++
//this code is executed in thread A
closesocket(socketB);
I expect this code will cause recv function to immediately return with value -1 or 0, breaking the loop, and finally terminating thread B. It works fine many times, and crashes some times, stopping the service. Is this a correct way to disconnect a client? If not, what is the correct way? What happens if thread A closes socket B when socket B is not waiting, for example, When thread B is executing myFunc1 in this code:
C++
while (1)
{
  int iResult = recv(socketB, buf, len, flags);
  if (iResult <= 0) break;
  myFunc1(buf, iResult);
}
Thanks in advance
mr.abzadeh
Posted
Updated 11-Mar-14 5:43am
v2
Comments
Sergey Alexandrovich Kryukov 11-Mar-14 11:48am    
With C, this problem is much harder than it may seem. If it was some language with exceptions, I would highly recommend my approach: non-graceful disconnection. This is because exceptional disconnections are unavoidable anyway (anything accidental: computer or application shutdown, broken network), so it's better to handle non-graceful disconnections on regular basics. With C, you have to proceed with care...
—SA
pasztorpisti 11-Mar-14 19:18pm    
This is not a socket programming problem but a multithreading problem. Learning multithreading has a steep curve, noone will be able to teach it to you here in an answer. Normally You shouldn't use the same socket handle from two threads. The handle should be used only by the thread that serves the client. If you want to stop the servicing of the client from another "manager thread" then you should signal the other thread to stop servicing, the other thread should receive the signal and as a result it should close its socket and terminate. How do you signal? This is that difficult part, you have to learn multithreading and also some OS specific APIs. There are many good solutions when it comes to multithreading and socket handling. On windows you can find good solutions/tutorials by searching with google for tutorials that make use of the following socket handling functions on windows: WSAEventSelect WSACreateEvent WSAWaitForMultipleEvents
mr.abzadeh 7-Apr-14 8:34am    
Thanks for your good help. I agree this is a multithreading problem. I redesigned my synchronization points completely, and removed some extra threads. Now my service program works smoothly, no crashing. The only question arising from your reply is this: If the socket to be managed is in blocking mode(recv called), How can we tell the thread to close the socket and terminate without accessing socket from the manager thread?
mr.abzadeh 7-Apr-14 8:42am    
No question. I'll use WSACreateEvent for that. Will you please post this as a answer so I can accept your answer and close the question? This question is open and I do not know to close the question.

Use the following set of functions: WSAEventSelect, WSACreateEvent, WSAWaitForMultipleEvents. Note that WSAEventSelect automatically puts your socket into nonblocking mode but this isnt a problem as you will block using WSAWaitForMultipleEvents and you can wake it up by using an event you create using WSACreateEvent (you have found that out correctly). Since your sockets are nonblocking always handle WSAEWOULDBLOCK errors when you do something with the socket (like recv/send) because WSAEWOULDBLOCK isn't really an error, its natural to receive this error in case of nonblocking sockets. There is another very big mistake you can commit in case of using WSAEventSelect + WSACreateEvent + WSAWaitForMultipleEvents: The signaling of these functions about socket-became-writable event is edge triggered (while the rest of the events are handled in level triggered mode). If you don't know what level/edge triggered means:

If you want to write the socket but its send buffer is full then you start waiting for the socket with the above apis. When some free space becomes available in the write buffer of the socket the system sends you an event about this. BUT since the socket-became-writable event is an edge triggered event if you don't write to the socket until its send buffer is full then even if you start waiting for another socket-became-writable event you will never receive it because it is sent by the system only when the send buffer of the socket fills up (transitions from non-full to full). For this reason you should handle the socket-writable event this way: Keep a "socket_writable" bool somewhere and set it to true initially. When you have data to write check this bool value: if its true then simply start writing the data to the socket otherwise start waiting for a write event. If you are writing the socket and its send buffer fills up (you receive WSAEWOULDBLOCK) store the remaining data somewhere and set the "socket_writable" flag of the socket to false and start waiting for a socket-writable event.

Summing it up: The best you can do is assuming that the socket is writable and if you receive WSAEWOULDBLOCK while trying to write the socket then its time to start waiting for the socket-writable event. We have just used a bool value to save some system calls if we know that the socket isn't currently in a writable state so sending data to it would return WSAEWOULDBLOCK for sure. A naive non-optimized implementation would always call send on the socket and it would store the data for later send if the current one failed with WSAEWOULDBLOCK.
 
Share this answer
 
v2
This actually should work fine (at least the socket portion)... the crashing may be due to something else related to synchronicity of the threads.

One thing is for sure though, on a blocking socket, closing the socket WILL always return from the recv() call (at least in Windows, Wine implementations don't do this, but if you're Windows only, it shouldn't be a problem).

From the recv() description from MSDN:
Quote:
If the socket is connection oriented and the remote side has shut down the connection gracefully, and all data has been received, a recv will complete immediately with zero bytes received. If the connection has been reset, a recv will fail with the error WSAECONNRESET.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900