Asynchrounous sockets doubts
-
I'm new in sockets programming especially in the asynchronous sockets. I'm writing a server and client apps with asynchronous sockets to (of course) exchange data between them. This is the code for the client app:
int SocketClient::CreateSocket(HWND hwnd) { char cName[20]; hostent * hostInfo; WSADATA wsStartup; WORD wVersion = MAKEWORD(2, 0); WSAStartup(wVersion, &wsStartup); currSocket = socket(AF_INET, SOCK_STREAM, 0); if(currSocket == INVALID_SOCKET) { MessageBox(NULL, "Socket não criado", "Erro", MB_OK); return -1; } gethostname(cName, 20); hostInfo = gethostbyname(cName); for(int i = 0 ; i < 8 ; i++)infosSocket.sin_zero[i] = 0; infosSocket.sin_family = AF_INET; infosSocket.sin_port = htons(2500); infosSocket.sin_addr = *((in_addr*)hostInfo->h_addr_list[0]); WSAAsyncSelect(currSocket, hwnd, WM_ASYNCMSG, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE); return 0; } int SocketClient::ConnectToServer(HWND hwnd) { int iReturn = 0; iReturn = connect(currSocket, (sockaddr*)&infosSocket, sizeof(infosSocket)); if(iReturn == SOCKET_ERROR) { char cTemp[10]; int iResult = WSAGetLastError(); itoa(iResult, cTemp, 10); MessageBox(NULL, cTemp, "", MB_OK); return -1; } WSAAsyncSelect(currSocket, hwnd, WM_ASYNCMSG, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE); MessageBox(NULL, "OK", "", MB_OK); return 0; }
And this is the server code:int SocketServer::CreateSocket(HWND hwnd) { SocketServer::iBytesRecieved = 0; int iReturn = 0; WSADATA wsStartup; WORD wVersion = MAKEWORD(2,0); WSAStartup(wVersion, &wsStartup); currSocket = socket(AF_INET, SOCK_STREAM, 0); //Cria o socket if(currSocket == INVALID_SOCKET) { MessageBox(NULL, "Socket não criado", "Erro", MB_OK); return -
-
I'm new in sockets programming especially in the asynchronous sockets. I'm writing a server and client apps with asynchronous sockets to (of course) exchange data between them. This is the code for the client app:
int SocketClient::CreateSocket(HWND hwnd) { char cName[20]; hostent * hostInfo; WSADATA wsStartup; WORD wVersion = MAKEWORD(2, 0); WSAStartup(wVersion, &wsStartup); currSocket = socket(AF_INET, SOCK_STREAM, 0); if(currSocket == INVALID_SOCKET) { MessageBox(NULL, "Socket não criado", "Erro", MB_OK); return -1; } gethostname(cName, 20); hostInfo = gethostbyname(cName); for(int i = 0 ; i < 8 ; i++)infosSocket.sin_zero[i] = 0; infosSocket.sin_family = AF_INET; infosSocket.sin_port = htons(2500); infosSocket.sin_addr = *((in_addr*)hostInfo->h_addr_list[0]); WSAAsyncSelect(currSocket, hwnd, WM_ASYNCMSG, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE); return 0; } int SocketClient::ConnectToServer(HWND hwnd) { int iReturn = 0; iReturn = connect(currSocket, (sockaddr*)&infosSocket, sizeof(infosSocket)); if(iReturn == SOCKET_ERROR) { char cTemp[10]; int iResult = WSAGetLastError(); itoa(iResult, cTemp, 10); MessageBox(NULL, cTemp, "", MB_OK); return -1; } WSAAsyncSelect(currSocket, hwnd, WM_ASYNCMSG, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE); MessageBox(NULL, "OK", "", MB_OK); return 0; }
And this is the server code:int SocketServer::CreateSocket(HWND hwnd) { SocketServer::iBytesRecieved = 0; int iReturn = 0; WSADATA wsStartup; WORD wVersion = MAKEWORD(2,0); WSAStartup(wVersion, &wsStartup); currSocket = socket(AF_INET, SOCK_STREAM, 0); //Cria o socket if(currSocket == INVALID_SOCKET) { MessageBox(NULL, "Socket não criado", "Erro", MB_OK); return -
Alex Cutovoi wrote:
The SendData and RecieveData funcs that contains send and recv funcs respectively, needs to be in a thread for that FD_READ and FD_WRITE messages will be sended?
Since you've used WSAAsyncSelect() specifying the FD_READ and FD_WRITE flags you will be notified when there is data available to be read from the socket and when the socket is ready to accept send data. This notification will be in the form of a window message (WM_ASYNCMSG) so you could send/recv data on the UI htread that processes this message. You can also send/recv on other threads. Just make sure you use some form of synchronization - sockets ops are not thread safe.
Alex Cutovoi wrote:
In the ConnectToServer func, when I start the server and the client app, I've received WSAEWOULDBLOCK message. If I call this funcition again I receive the WSAEISCONN message. This means that my socket is connected? If so, why I receive the WSAEWOULDBLOCK message first?
WSAEWOULDBLOCK indicates that an asynchronous socket operation has started but didn't complete immediately. If you want to be notified when a connect() call completes then you should add the FD_CONNECT flag to your WSAAsyncSelect() flags.
Alex Cutovoi wrote:
In some sites that I've readed some tutorials, they say that, in the FD_WRITE message I need to have some caution because this message is sent when there are more space in the buffer with which to write data. Can someone explains tis to me?
Read the details of using FD_WRITE carefully in the docs. From WSAAsyncSelect() - "The FD_WRITE event is handled slightly differently. An FD_WRITE message is posted when a socket is first connected with connect or WSAConnect (after FD_CONNECT, if also registered) or accepted with accept or WSAAccept, and then after a send operation fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an application can assume that sends are possible starting from the first FD_WRITE message and lasting until a send returns WSAEWOULDBLOCK. After such a failure the application will be notified that sends are again possible with an FD_WRITE message." Always check the return code on send() and recv() calls to make sure the number of bytes requested were actually sent or received. A send() or recv() is successful even if only ONE byte gets sent or received. You'll need to
-
Alex Cutovoi wrote:
The SendData and RecieveData funcs that contains send and recv funcs respectively, needs to be in a thread for that FD_READ and FD_WRITE messages will be sended?
Since you've used WSAAsyncSelect() specifying the FD_READ and FD_WRITE flags you will be notified when there is data available to be read from the socket and when the socket is ready to accept send data. This notification will be in the form of a window message (WM_ASYNCMSG) so you could send/recv data on the UI htread that processes this message. You can also send/recv on other threads. Just make sure you use some form of synchronization - sockets ops are not thread safe.
Alex Cutovoi wrote:
In the ConnectToServer func, when I start the server and the client app, I've received WSAEWOULDBLOCK message. If I call this funcition again I receive the WSAEISCONN message. This means that my socket is connected? If so, why I receive the WSAEWOULDBLOCK message first?
WSAEWOULDBLOCK indicates that an asynchronous socket operation has started but didn't complete immediately. If you want to be notified when a connect() call completes then you should add the FD_CONNECT flag to your WSAAsyncSelect() flags.
Alex Cutovoi wrote:
In some sites that I've readed some tutorials, they say that, in the FD_WRITE message I need to have some caution because this message is sent when there are more space in the buffer with which to write data. Can someone explains tis to me?
Read the details of using FD_WRITE carefully in the docs. From WSAAsyncSelect() - "The FD_WRITE event is handled slightly differently. An FD_WRITE message is posted when a socket is first connected with connect or WSAConnect (after FD_CONNECT, if also registered) or accepted with accept or WSAAccept, and then after a send operation fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an application can assume that sends are possible starting from the first FD_WRITE message and lasting until a send returns WSAEWOULDBLOCK. After such a failure the application will be notified that sends are again possible with an FD_WRITE message." Always check the return code on send() and recv() calls to make sure the number of bytes requested were actually sent or received. A send() or recv() is successful even if only ONE byte gets sent or received. You'll need to
Thanks again Mark, I've suspected that WSAEWOULDBLOCK message indicates what you said. I comproved this studying some code samples and noticing the WSAEISCONN message. Just a question of pay attention. FYI, I'm developing my apps with Win32, not a single gout of MFC. I'm very new in this subject, I'm developing my app based on your answer about my question of sockets: Socket curious error Very thanks. I have some questions yet:
Mark Salsbery wrote:
Since you've used WSAAsyncSelect() specifying the FD_READ and FD_WRITE flags you will be notified when there is data available to be read from the socket and when the socket is ready to accept send data. This notification will be in the form of a window message (WM_ASYNCMSG) so you could send/recv data on the UI thread that processes this message. You can also send/recv on other threads. Just make sure you use some form of synchronization - sockets ops are not thread safe.
So, do I need to put the SendData and RecieveData functions in a thread right? Can you give me a sample?
Mark Salsbery wrote:
Always check the return code on send() and recv() calls to make sure the number of bytes requested were actually sent or received. A send() or recv() is successful even if only ONE byte gets sent or received. You'll need to be ready to send remaining unsent bytes and/or receive remaining unreceived bytes.
This is the hard part, how can I check in app there unsent bytes? This is a topic that I don't domain yet, I'll be very grateful if you can answer my questions again.
-
Thanks again Mark, I've suspected that WSAEWOULDBLOCK message indicates what you said. I comproved this studying some code samples and noticing the WSAEISCONN message. Just a question of pay attention. FYI, I'm developing my apps with Win32, not a single gout of MFC. I'm very new in this subject, I'm developing my app based on your answer about my question of sockets: Socket curious error Very thanks. I have some questions yet:
Mark Salsbery wrote:
Since you've used WSAAsyncSelect() specifying the FD_READ and FD_WRITE flags you will be notified when there is data available to be read from the socket and when the socket is ready to accept send data. This notification will be in the form of a window message (WM_ASYNCMSG) so you could send/recv data on the UI thread that processes this message. You can also send/recv on other threads. Just make sure you use some form of synchronization - sockets ops are not thread safe.
So, do I need to put the SendData and RecieveData functions in a thread right? Can you give me a sample?
Mark Salsbery wrote:
Always check the return code on send() and recv() calls to make sure the number of bytes requested were actually sent or received. A send() or recv() is successful even if only ONE byte gets sent or received. You'll need to be ready to send remaining unsent bytes and/or receive remaining unreceived bytes.
This is the hard part, how can I check in app there unsent bytes? This is a topic that I don't domain yet, I'll be very grateful if you can answer my questions again.
Alex Cutovoi wrote:
So, do I need to put the SendData and RecieveData functions in a thread right? Can you give me a sample?
You don't need to but you can. If there's so much data being sent and received that it degrades the UI performance then it's probably a good idea. If you only transfer small amounts not very often then you could leave your send/recv calls on the UI thread.
Alex Cutovoi wrote:
This is the hard part, how can I check in app there unsent bytes?
The return value of the socket send() and recv() APIs are slightly different. Both return SOCKET_ERROR if an error occurs, which means no bytes were transferred. For an async socket if the error was WSAEWOULDBLOCK then it means data could't be transferred right away (no bytes were received or send buffer is full) so you'll need to try again. For send(), a successful return value is the number of bytes sent, which may not be all the bytes you requested to be sent. For recv(), a successful return value is the number of bytes received, which may not be all the bytes you requested to be received. If recv() returns 0 that means the connection has been closed. So, a generic example of handling these return values could be something like this:
int nBytesToRecv = ...; // number of bytes to receive
BYTE *pRecvBytes = ...; // pointer to bufer to receive bytes towhile (nBytesToRecv > 0)
{
int nBytesReceived = ::recv(sock, (char*)pRecvBytes, nBytesToRecv, 0);
if (nBytesReceived == SOCKET_ERROR)
{
int nSockError = ::WSAGetLastError();
if (nSockError != WSAEWOULDBLOCK)
{
// handle other (non-WSAEWOULDBLOCK) errors here
break;
}
}
else
{
nBytesToRecv -= nBytesReceived;
if (nBytesToRecv > 0)
pRecvBytes += nBytesReceived;
}
}"Great job, team. Head back to base for debriefing and cocktails." (Spottswoode "Team America")
-
Alex Cutovoi wrote:
So, do I need to put the SendData and RecieveData functions in a thread right? Can you give me a sample?
You don't need to but you can. If there's so much data being sent and received that it degrades the UI performance then it's probably a good idea. If you only transfer small amounts not very often then you could leave your send/recv calls on the UI thread.
Alex Cutovoi wrote:
This is the hard part, how can I check in app there unsent bytes?
The return value of the socket send() and recv() APIs are slightly different. Both return SOCKET_ERROR if an error occurs, which means no bytes were transferred. For an async socket if the error was WSAEWOULDBLOCK then it means data could't be transferred right away (no bytes were received or send buffer is full) so you'll need to try again. For send(), a successful return value is the number of bytes sent, which may not be all the bytes you requested to be sent. For recv(), a successful return value is the number of bytes received, which may not be all the bytes you requested to be received. If recv() returns 0 that means the connection has been closed. So, a generic example of handling these return values could be something like this:
int nBytesToRecv = ...; // number of bytes to receive
BYTE *pRecvBytes = ...; // pointer to bufer to receive bytes towhile (nBytesToRecv > 0)
{
int nBytesReceived = ::recv(sock, (char*)pRecvBytes, nBytesToRecv, 0);
if (nBytesReceived == SOCKET_ERROR)
{
int nSockError = ::WSAGetLastError();
if (nSockError != WSAEWOULDBLOCK)
{
// handle other (non-WSAEWOULDBLOCK) errors here
break;
}
}
else
{
nBytesToRecv -= nBytesReceived;
if (nBytesToRecv > 0)
pRecvBytes += nBytesReceived;
}
}"Great job, team. Head back to base for debriefing and cocktails." (Spottswoode "Team America")
Very thanks mike, I have a direction now. But one more thing, I want to send a struct between the apps. To fill the nBytesToRecv var, in my case, just I call the sizeof() func to fill it? Thanks for the help in this topic.
-
Very thanks mike, I have a direction now. But one more thing, I want to send a struct between the apps. To fill the nBytesToRecv var, in my case, just I call the sizeof() func to fill it? Thanks for the help in this topic.
Alex Cutovoi wrote:
To fill the nBytesToRecv var, in my case, just I call the sizeof() func to fill it?
Generally yes. As long as the two ends use the same byte ordering for multi-byte numeric types (int, etc.). Both ends should be compiled using the same structure padding as well. :) Mark
"Great job, team. Head back to base for debriefing and cocktails." (Spottswoode "Team America")
-
Alex Cutovoi wrote:
To fill the nBytesToRecv var, in my case, just I call the sizeof() func to fill it?
Generally yes. As long as the two ends use the same byte ordering for multi-byte numeric types (int, etc.). Both ends should be compiled using the same structure padding as well. :) Mark
"Great job, team. Head back to base for debriefing and cocktails." (Spottswoode "Team America")
Thanks mark, now I get some more knowledge to code my app