I am having problem in usage of recv function
I have an application that send some data from client, these data are received by the server & send a responses based on data.
The implementation works fine when I send less than ~16 requests.
But when I send more than 16 request (one after the other) from the client, the response are fine from the server until 16th request but after this the server hangs. I could see that the data are transmitted from client but are not received by server. I am using the function recv
The reception is happening in a loop which is exited only when termination request is received from the client.
Server Code:
// Request Winsock version 2.2
fprintf(stderr,"Performing WSAStartup\n");
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"FAILED with error %d\n", retval);
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
if (port == 0)
{
Usage(argv[0]);
}
/* open socket connection */
printf("Opening socket\n");
local.sin_family = AF_INET;
local.sin_addr.s_addr = (!ip_address) ? INADDR_ANY:inet_addr(ip_address);
/* Port MUST be in Network Byte Order */
local.sin_port = htons(port);
// TCP socket
listen_socket = socket(AF_INET, socket_type,0);
if (listen_socket == INVALID_SOCKET){
fprintf(stderr,"socket() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
// bind() associates a local address and port combination with the socket just created.
// This is most useful when the application is a
// server that has a well-known port that clients know about in advance.
printf("Bind address and port to socket\n");
if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
{
fprintf(stderr,"bind() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
// So far, everything we did was applicable to TCP as well as UDP.
// However, there are certain steps that do not work when the server is
// using UDP. We cannot listen() on a UDP socket.
if (socket_type != SOCK_DGRAM)
{
printf("TCP: listening on socket\n");
if (listen(listen_socket,5) == SOCKET_ERROR)
{
fprintf(stderr,"listen() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
}
//Perform Applcation task
//initisations
printf("Server is listening and waiting for a connection\non port %d, protocol %s\n",port, (socket_type == SOCK_STREAM)?"TCP":"UDP");
executeServer = 1;
while(executeServer == 1)
{
fromlen =sizeof(from);
// accept() doesn't make sense on UDP, since we do not listen()
if (socket_type != SOCK_DGRAM)
{
printf("TCP: Waiting for connection (accept())\n");
msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET)
{
fprintf(stderr,"accept() error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
printf("accepted connection from %s, port %d\n", inet_ntoa(from.sin_addr), htons(from.sin_port)) ;
}
}
else
{
msgsock = listen_socket;
}
// In the case of SOCK_STREAM, the server can do recv() and send() on
// the accepted socket and then close it.
// However, for SOCK_DGRAM (UDP), the server will do recvfrom() and sendto() in a loop.
printf("Receiving data");
if (socket_type != SOCK_DGRAM)
{
retval = recv(msgsock, Buffer, sizeof(Buffer), 0);
}
else
{
retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen);
printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
return -2;
}
else
{
printf("OK\n");
}
if (retval == 0)
{
printf("Client closed connection.\n");
closesocket(msgsock);
}
else
{
printf("Received %d bytes, data \"%s\" from client\n", retval, Buffer);
}
printf("Processing Data\n");
if (!stricmp(Buffer, "exit"))
{
wsprintf(AckBuffer,"ACK");
executeServer = 0;
}
else
{
// Perform use task here based on recieved data
}
printf("Sending answer to client\n");
if (socket_type != SOCK_DGRAM)
{
retval = send(msgsock, AckBuffer, sizeof(AckBuffer), 0);
}
else
{
retval = sendto(msgsock, AckBuffer, sizeof(AckBuffer), 0, (struct sockaddr *)&from, fromlen);
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"send() failed: error %d\n", WSAGetLastError());
}
else
{
printf("OK\n");
}
/* close TCP connection */
if (socket_type != SOCK_DGRAM)
{
closesocket(msgsock);
}
}
printf("terminating server\n");
closesocket(msgsock);
WSACleanup();
Client Code:
fprintf(stderr,"Performing WSAStartup");
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"WSAStartup() failed with error %d\n", retval);
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
if (port == 0)
{
Usage(argv[0]);
}
// Attempt to detect if we should call gethostbyname() or gethostbyaddr()
printf("Translate hastname to address -> gethostbyaddr()\n");
if (isalpha(server_name[0]))
{ // server address is a name
hp = gethostbyname(server_name);
}
else
{ // Convert nnn.nnn address to a usable one
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr, 4, AF_INET);
}
if (hp == NULL )
{
fprintf(stderr,"Cannot resolve address \"%s\": Error %d\n", server_name, WSAGetLastError());
WSACleanup();
exit(1);
}
else
{
printf("OK\n");
}
// Copy the resolved information into the sockaddr_in structure
printf("Opening socket\n");
memset(&server, 0, sizeof(server));
memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
server.sin_family = hp->h_addrtype;
server.sin_port = htons(port);
conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */
if (conn_socket <0 )
{
fprintf(stderr,"Error Opening socket: Error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
// Notice that nothing in this code is specific to whether we
// are using UDP or TCP.
// We achieve this by using a simple trick.
// When connect() is called on a datagram socket, it does not
// actually establish the connection as a stream (TCP) socket
// would. Instead, TCP/IP establishes the remote half of the
// (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
// This enables us to use send() and recv() on datagram sockets,
// instead of recvfrom() and sendto()
printf("Client connecting to: %s.\n", hp->h_name);
if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
fprintf(stderr,"connect() failed: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
/* copy options string to buffer */
strcpy(Buffer,Options);
printf("Sending Data \"%s\"\n", Buffer);
retval = send(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"send() failed: error %d.\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
printf("Receiving status from server\n");
retval = recv(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"recv() failed: error %d.\n", WSAGetLastError());
closesocket(conn_socket);
WSACleanup();
return -1;
}
else
{
printf("OK\n");
}
// We are not likely to see this with UDP, since there is no
// 'connection' established.
if (retval == 0)
{
printf("Client: Server closed connection.\n");
closesocket(conn_socket);
WSACleanup();
return -1;
}
printf("Received %d bytes, data \"%s\" from server.\n", retval, Buffer);
closesocket(conn_socket);
WSACleanup();
If you use recv without making your socket non-blocking mode, your recv is doing a right thing. It blocks until it has something to read.
[UPDATE]
From the code, you are indeed using blocking socket. I recommend you use non-blocking socket at least for your server. I believe you can easily google how to make non-blocking socket and handle async IO in Windows. Good Luck!
[UPDATE2]
First of all, your server code seems to close connection once recv reads something. Since TCP does not care data boundary, you can't just close the connection. Remember one send call in client may require multiple recv calls in server with TCP or vice versa.
For your specific problem, I'm pretty sure there is nothing to read and that's why recv is blocking your program. Make it sure that your client really sends something successfully.
Related
I'm using VC++ on Visual Studio 2010.
Now I've got some problem. I think it's so silly question but I want to get a clear answer.
How can I get CLOSE_WAIT state of an selected SOCKET?
// SocketThreadConn.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <WinSock.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PR_RECORED_TIME 10*1000 // (ms)
BYTE* pByteCamData = NULL;
INT nHeight = 900;
INT nWidth = 1600;
INT nSpect = 3;
INT nSolution = nHeight * nWidth * nSpect;
VOID SendRecoredData(SOCKET socket2operation);
int _tmain(int argc, _TCHAR* argv[])
{
pByteCamData = new BYTE[nSolution]; // <-- use [], not ()!
//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error: %d\n", iResult);
delete[] pByteCamData;
return 1;
}
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service = {};
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY; // inet_addr("127.0.0.1");
service.sin_port = htons(27015);
if (bind(ListenSocket, (SOCKADDR *) &service, sizeof(service)) == SOCKET_ERROR) {
wprintf(L"bind failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen(ListenSocket, 1) == SOCKET_ERROR) {
wprintf(L"listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// Accept the connection.
wprintf(L"Waiting for client to connect...\n");
SOCKET AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
wprintf(L"accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
wprintf(L"Client connected.\n");
SendRecoredData(AcceptSocket); // <-- logic fix!
// No longer need client socket
closesocket(AcceptSocket); // <-- CLOSE_WAIT fix!
// No longer need server socket
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 0;
}
VOID SendRecoredData(SOCKET socket2operation)
{
if(IsSocketAlive(socket2operation) == 0)
return;
INT nCountDown = 5;
INT nSentData, nNumToSend;
BYTE *pData;
do
{
if (nCountDown == 0)
{
nCountDown = 5;
pData = pByteCamData;
nNumToSend = nSolution;
while (nNumToSend > 0) <-- send() fix!
{
nSentData = send(socket2operation, (char*)pData, nNumToSend, 0);
if (SOCKET_ERROR == nSentData) {
wprintf(L"send failed with error: %d\n", WSAGetLastError());
return;
}
pData += nSentData;
nNumToSend -= nSentData;
}
wprintf(L"Sent Camera Data OK [%d] Bytes\n", nSolution);
}
Sleep(PR_RECORED_TIME);
--nCountDown;
}
while (TRUE);
}
INT IsSocketAlive(SOCKET socket2check)
{
if (socket2check == INVALID_SOCKET)
return FALSE;
INT nError_code = -1;
INT nError_code_size = sizeof(nError_code);
INT nRetValue = getsockopt(socket2check, SOL_SOCKET, SO_ERROR, (CHAR*)&nError_code, &nError_code_size);
// if (nRetValue != -1)
{
// _tprintf(_T("Error getting socket error code : %d \n"), strerror(nRetValue));
}
if (nError_code != 0)
{
_tprintf(_T("Socket error : %d \n"), strerror(nError_code));
}
switch (nError_code)
{
case 0:
return TRUE;
break;
case SOCKET_ERROR:
return FALSE;
default:
return FALSE;
}
}
A problem is CLOSE_WAIT 'ed' socket is checked as alive socket.
When SocketThreadConn.exe is working on while loop, it doesn't break loop though Listen socket is CLOSE_WAIT.
How can I check accepted socket is ESTABLISHED?
(This code has changed by #Remy Lebeau)
How can I check is a socket is still ESTABLISHED not using send() or GetTcpTable().
Function GetTcpTable() is working well but I have to find socket only using their value(USHORT). There is no field for socket value in MIB_TCPTABLE.
#define SOCKET_ALIVE 10
#define SOCKET_DEAD 9
INT CheckSocketAlive(SOCKET socket2check)
{
fd_set fdR;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&fdR);
FD_SET(socket2check, &fdR);
switch (select(socket2check + 1, &fdR, NULL,NULL, &timeout))
{
case SOCKET_ERROR:
_tprintf(_T("\tError condition. Code : [%d]\n"), WSAGetLastError());
return SOCKET_DEAD;
case 0:
return SOCKET_ALIVE;
default:
if ( FD_ISSET(socket2check, &fdR) )
{
_tprintf(_T("A read event has occurred on socket [socket2check].\n"));
return SOCKET_DEAD;
}
break;
}
}
You can get state of selected socket using this function.
But only SOCKET_ERROR or SOCKET_ALIVE.
You can change timeout.tv_sec (1sec) as you want.
How can I get CLOSE_WAIT state of an selected SOCKET?
There is no Winsock API for that particular purpose. However, you can retrieve the SOCKET's two IP/port pairs (via getsockname() and getpeername()) and then look for them in the output of GetTcpTable() or related function. That will give you the current state, and even the owning process.
But, there is a bug in your code that is causing the CLOSE_WAIT state - you are not closing the SOCKET returned by accept(). CLOSE_WAIT means an established connection received a FIN from the other peer, and is waiting for you to send a FIN and close your SOCKET handle for the connection.
Fix that bug, and you won't need to resort to using GetTcpTable() at all.
How can I check accepted socket is ESTABLISHED?
You could use GetTcpTable() for that as well. However, the best way is to just perform actual I/O over the connection and see if it succeeds or fails. Your IsSocketAlive() function is incorrect and useless as-is. Use the return value from send() to know if the socket is still alive (since you are not reading any data from the client).
With that said, there are other bugs in your code, too.
You are not allocating pByteCamData correctly. You need to use [] instead of (). You are allocating a single BYTE with nSolution as its value, not an array of nSolution number of bytes.
You are passing the listening SOCKET to SendRecoredData(), but you should be passing the SOCKET from accept() instead.
send() is not guaranteed to send all of the requested bytes in a single go. It can send fewer bytes than requested (which is likely since you are trying to send > 4MB at a time). If the return value is less than the number of bytes requested, you have to call send() again to send the remaining bytes. So, call send() in a loop until there are no more bytes to send.
Try something more like this:
// SocketThreadConn.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <WinSock.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PR_RECORED_TIME 10*1000 // (ms)
BYTE* pByteCamData = NULL;
INT nHeight = 900;
INT nWidth = 1600;
INT nSpect = 3;
INT nSolution = nHeight * nWidth * nSpect;
VOID SendRecoredData(SOCKET socket2operation);
int _tmain(int argc, _TCHAR* argv[])
{
pByteCamData = new BYTE[nSolution]; // <-- use [], not ()!
//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error: %d\n", iResult);
delete[] pByteCamData;
return 1;
}
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service = {};
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY; // inet_addr("127.0.0.1");
service.sin_port = htons(27015);
if (bind(ListenSocket, (SOCKADDR *) &service, sizeof(service)) == SOCKET_ERROR) {
wprintf(L"bind failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen(ListenSocket, 1) == SOCKET_ERROR) {
wprintf(L"listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
//----------------------
// Accept the connection.
wprintf(L"Waiting for client to connect...\n");
SOCKET AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
wprintf(L"accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 1;
}
wprintf(L"Client connected.\n");
SendRecoredData(AcceptSocket); // <-- logic fix!
// No longer need client socket
closesocket(AcceptSocket); // <-- CLOSE_WAIT fix!
// No longer need server socket
closesocket(ListenSocket);
WSACleanup();
delete[] pByteCamData;
return 0;
}
VOID SendRecoredData(SOCKET socket2operation)
{
INT nCountDown = 5;
INT nSentData, nNumToSend;
BYTE *pData;
do
{
if (nCountDown == 0)
{
nCountDown = 5;
pData = pByteCamData;
nNumToSend = nSolution;
while (nNumToSend > 0) <-- send() fix!
{
nSentData = send(socket2operation, (char*)pData, nNumToSend, 0);
if (SOCKET_ERROR == nSentData) {
wprintf(L"send failed with error: %d\n", WSAGetLastError());
return;
}
pData += nSentData;
nNumToSend -= nSentData;
}
wprintf(L"Sent Camera Data OK [%d] Bytes\n", nSolution);
}
Sleep(PR_RECORED_TIME);
--nCountDown;
}
while (TRUE);
}
SendRecoredData(ListenSocket);
That should be
SendRecoredData(AcceptSocket);
which would have been causing an error in send() that you haven't told us about, and you are never closing AcceptSocket. That's what's causing the CLOSE_WAIT states. You don't need to look for them explicitly. Just fix your bugs.
I've been doing the Winsock tutorials and following it exactly. I can't seem to get either send() or recv() to function properly. I have a basic Server and Client program set up, and the connection is being made, but the Server isn't sending a message to the Client. Using the Telnet client also doesn't receive a response from the server. I'm not really sure what's happening, and all the questions I looked at were not basic or had stuff I couldn't really understand what they were doing.
Server.cpp
#include<WinSock2.h>
#include <io.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c;
char *message;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
else
printf("Initialised.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 2;
}
else
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : &d", WSAGetLastError());
return 3;
}
else
puts("Bind done");
//listen
listen(s, 3);
//accept an incoming connection
puts("Waiting for incoming connections...");
c = sizeof(sockaddr_in);
while (new_socket = accept(s, (sockaddr *)&client, &c) != INVALID_SOCKET)
{
printf("Connect successful...\n");
//reply to the client
message = "Hello Client, I have recieved your connection, but I have to go now, bye!\n";
send(new_socket, message, strlen(message), 0);
puts("Message sent.\n");
}
if (new_socket == INVALID_SOCKET)
{
printf("accept() failed with error code : %d", WSAGetLastError());
return 4;
}
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
Client.cpp
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <IPHlpApi.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
int main(int argc, char *argv[])
{
//intialize variables
WSADATA wsa;
char ip[100] = "192.168.1.117";
SOCKET s;
sockaddr_in server;
char *message, server_reply[75];
int recv_size;
//initialize Winsock
printf("\nInitialising Winsock...\n");
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//create the socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 3;
}
printf("Socket created.\n");
server.sin_addr.S_un.S_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(8888);
//connect to the server
if (connect(s, (sockaddr *)&server, sizeof(server)) < 0)
{
puts("connect error");
return 4;
}
else
{
printf("Connect successful");
recv_size = recv(s, server_reply, 75, 0);
}
if (recv_size <= 0)
{
puts("recv() failed\n");
}
else
{
//add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
}
getchar();
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
The client also fails to print the "recv() failed" line; it's like it's stuck at the recv() call.
On the server side:
you are not checking the return value of listen() for error.
you are not resetting c on each call to accept(), and you are not calling closesocket() on each client that is accepted.
you are not checking the return value of send() for error.
Try this instead:
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c, res, messagelen;
const char *message;
printf("\nInitializing Winsock...");
res = WSAStartup(MAKEWORD(2,2), &wsa);
if (res != 0)
{
printf("Failed. Error: %d\n", res);
return 1;
}
printf("Initialized.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket. Error: %d\n", WSAGetLastError());
return 2;
}
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed. Error: &d", WSAGetLastError());
return 3;
}
printf("Bind done.\n");
//listen
if (listen(s, 3) == SOCKET_ERROR)
{
printf("Listen failed. Error: &d", WSAGetLastError());
return 4;
}
printf("Listening.\n");
//accept incoming connections
printf("Waiting for incoming connections...\n");
do
{
c = sizeof(sockaddr_in);
new_socket = accept(s, (sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("Failed to accept a client. Error: %d\n", WSAGetLastError());
return 5;
}
printf("Client connected...\n");
//reply to the client
message = "Hello Client, I have received your connection, but I have to go now, bye!\n";
messagelen = strlen(message);
do
{
res = send(new_socket, message, messagelen, 0);
if (res == SOCKET_ERROR)
{
printf("Failed to send message. Error: %d\n", WSAGetLastError());
break;
}
message += res;
messagelen -= res;
}
while (messagelen > 0);
if (messagelen == 0)
printf("Message sent.\n");
//close the client socket
closesocket(new_socket);
}
while (true);
//close the server socket
closesocket(s);
WSACleanup();
return 0;
}
On the client side, the only real problem I see is your recv() call has a potential buffer overflow waiting to happen, since you ask it to read 75 bytes, and that is the exact size of your buffer. It just happens that your server is only sending 74 bytes max, but if it ever sent more, you could overflow the buffer when appending the '\0' terminator to it.
So, either:
call recv() with sizeof(server_reply)-1 as the buffer size, to give yourself room for the added terminator:
recv_size = recv(s, server_reply, sizeof(server_reply)-1, 0);
use printf() instead of puts() so you don't need to null-terminate the buffer at all when printing it to the console. You can pass recv_size as a parameter to limit the amount of text being printed:
//server_reply[recv_size] = '\0';
//puts(server_reply);
printf("%.*s", recv_size, server_reply);
From the MSDN documentation on closesocket():
Note To assure that all data is sent and received on a connection, an application should call shutdown before calling closesocket (see Graceful shutdown, linger options, and socket closure for more information). Also note, an FD_CLOSE network event is not posted after closesocket is called.
Basically the data you have sent was still pending when you closed the socket.
I am writting a small server application which has ServerSocket object waiting for and create connection socket.
Each connection has a SocketListener and a SocketSender for transfering data.
Each SocketListener is a separate thread. When a connection is disconnect by client, SocketListener send a message to ServerSocket notify that it is closing, so that ServerSocket can clear the handle for that connection from a list.
However, don't know why the message is not received by SocketListener thread. I have tried to narrow down the message filter, but no luck. Could someone help me with this.
DWORD ServerSocket::m_ThreadFunc() {
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed\n");
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT_STR, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed\n");
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed\n");
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed\n");
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed\n");
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// allow listener thread to report back its state
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
//force create message queue
PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_NOREMOVE);
printf("Listing for clients on port %s \n", DEFAULT_PORT_STR);
while (listening) {
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket != INVALID_SOCKET) {
printf("Client connected\n");
sender = new SocketSender(ClientSocket);
listener = new SocketListener(ClientSocket, this->m_threadId);
printf("Listener created\n");
listener->setSender(sender);
listener->startThread();
printf("Listener started\n");
listenerList.push_back(listener);
senderList.push_back(sender);
printf("Listener list size: %d \n", listenerList.size());
printf("Listener pushed to list\n");
//delete socket data if listener close itself due to connection lost or disconnect.
}
else {
int error = WSAGetLastError();
printf("accept failed\n");
switch (error) {
case 10093:
listening = false;
try {
closesocket(ListenSocket);
}
catch (...) {}
return 1;
}
}
printf("Check message queue for thread message\n");
//check thread message queue
//GetMessage(&msg, NULL, 0, 0); //this blocks untill a message is get.
PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_REMOVE);
if (msg.message == WM_USER + 1)
{
//ProcessCustomMessage(msg);
m_deleteListener((SocketListener*)msg.wParam);
printf("Recieved message from ThreadID: %d \n", msg.wParam);
}
printf("Recieved message from ThreadID: %d \n", msg.message);
printf("Server socket complete 1 loop\n");
}
return 0;
}
DWORD SocketListener::m_ThreadFunc() {
listening = true;
rapidxml::xml_document<> doc;
printf("Start thread with ID: %d \n", this->m_threadId);
printf("Parent Thread ID: %d \n", this->_iParentID);
while (listening) {
int iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
recvbuf[iResult - 1] = 0; // null terminate the string according to the length
// The message spec indicates the XML will end in a "new line"
// character which can be either a newline or caraiage feed
// Search for either and replace with a NULL to terminate
if (recvbuf[iResult - 2] == '\n' || recvbuf[iResult - 2] == '\r')
recvbuf[iResult - 2] = 0;
try {
doc.parse<0>(&recvbuf[0]);
HandleXMLMessage(&doc);
}
catch (...) {}
}
else {
printf("Thread %d is being closed, sending signal to parent (%d)\n", this->m_threadId, this->_iParentID);
if (PostThreadMessage(this->_iParentID, WM_APP + 1, NULL, NULL) == 0)
{
printf("Client cant send Message before closing the conn ! \n");
printf("Last error %d", GetLastError());
}
else {
printf("Client sent Closing Message successfully \n");
}
closesocket(ClientSocket);
return 1;
}
}
printf("Server terminate connection\n");
printf("Thread %d is closed, sending signal to parent (%d)\n", this->m_threadId,this->_iParentID);
PostThreadMessage(this->_iParentID, WM_USER + 1, (WPARAM)this->m_threadId, NULL);
return 0;
}
Thank you very much.
accept function is a blocking call, so it looks like after accepting first connection your loop gets stuck at
ClientSocket = accept(ListenSocket, NULL, NULL);
And does not check thread message queue until the next connection is made.
You also need to check the return result of PeekMessage to know whether message was actually peeked otherwise msg variable will contain garbage.
I'm now facing the problem of C++ winsock server programming for receiving messages from both TCP and UDP. In fact, UDP is used for receiving the job message from another server, while TCP receives messages from multiple RFID receivers.
So I've googled for days to see what approach I can use, and I found the followings:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738620(v=vs.85).aspx
http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch08lev1sec15.html
However, I still cannot come up with the clear flow that how I can start the server application without selecting either TCP or UDP by the command line arguement i.e. I just want to start the winsock server program with creating both TCP and UDP sockets and then wait for connections.
So, according to the above two links, how can I do for the purpose I stated above i.e. how can I initialize the TCP and UDP sockets when I start the program and then go into the while loop for waiting the connections? Thanks!
Edited 20150918 4:12pm HKT
I've tried to combine the examples in two links provided above, but it is work for TCP while not in UDP. What is the problem for UDP according to the following server and client codes? Thanks!
server.cpp
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#define STRICMP _stricmp
#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP
void Usage(char *progname) {
fprintf(stderr, "Usage\n%s -e [endpoint] -i [interface]\n",
progname);
fprintf(stderr, "Where:\n\tendpoint is the port to listen on\n");
fprintf(stderr, "\tinterface is the ipaddr (in dotted decimal notation)");
fprintf(stderr, " to bind to\n");
fprintf(stderr, "Defaults are 5001 and INADDR_ANY\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {
char Buffer[128];
char *interface = NULL;
unsigned short port = DEFAULT_PORT;
int retval;
int fromlen;
int i;
int maxfdp1, nready;
struct sockaddr_in local, from;
WSADATA wsaData;
SOCKET listen_socket, udp_socket, msgsock;
fd_set SockSet;
/* Parse arguments */
if (argc >1) {
for (i = 1; i <argc; i++) {
if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
switch (tolower(argv[i][1])) {
case 'i':
interface = argv[++i];
break;
case 'e':
port = (unsigned short)atoi(argv[++i]);
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
if ((retval = WSAStartup(0x202, &wsaData)) != 0) {
fprintf(stderr, "WSAStartup failed with error %d\n", retval);
WSACleanup();
return -1;
}
if (port == 0){
Usage(argv[0]);
}
local.sin_family = AF_INET;
local.sin_addr.s_addr = (!interface) ? INADDR_ANY : inet_addr(interface);
/*
* Port MUST be in Network Byte Order
*/
local.sin_port = htons(port);
listen_socket = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
if (listen_socket == INVALID_SOCKET){
fprintf(stderr, "socket() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local))
== SOCKET_ERROR) {
fprintf(stderr, "TCP bind() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
if (listen(listen_socket, 5) == SOCKET_ERROR) {
fprintf(stderr, "TCP listen() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("TCP listen() established\n");
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (bind(udp_socket, (struct sockaddr*)&local, sizeof(local))
== SOCKET_ERROR) {
fprintf(stderr, "UDP bind() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("UDP bind() established\n");
FD_ZERO(&SockSet);
maxfdp1 = max(listen_socket, udp_socket) + 1;
while (1) {
fromlen = sizeof(from);
FD_SET(listen_socket, &SockSet);
FD_SET(udp_socket, &SockSet);
if ((nready = select(maxfdp1, &SockSet, NULL, NULL, NULL)) < 0)
fprintf(stderr, "select() failed with error %d\n", WSAGetLastError());
if (FD_ISSET(listen_socket, &SockSet))
{
msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET)
{
fprintf(stderr, "accept() error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("TCP msgsock=%d listen_socket=%d\n", msgsock, listen_socket);
printf("accepted connection from %s, port %d\n",
inet_ntoa(from.sin_addr),
htons(from.sin_port));
retval = recv(msgsock, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
continue;
}
if (retval == 0) {
printf("Client closed connection\n");
closesocket(msgsock);
continue;
}
printf("Received %d bytes, data [%s] from client\n", retval, Buffer);
printf("Echoing same data back to client\n");
retval = send(msgsock, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
}
printf("Terminating connection\n");
closesocket(msgsock);
}
else if (FD_ISSET(udp_socket, &SockSet))
{
retval = recvfrom(msgsock, Buffer, sizeof(Buffer), 0,
(struct sockaddr *)&from, &fromlen);
printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));
if (retval == SOCKET_ERROR) {
fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
continue;
}
if (retval == 0) {
printf("Client closed connection\n");
closesocket(msgsock);
continue;
}
printf("Received %d bytes, data [%s] from client\n", retval, Buffer);
printf("Echoing same data back to client\n");
retval = sendto(msgsock, Buffer, sizeof(Buffer), 0,
(struct sockaddr *)&from, fromlen);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
}
printf("UDP server looping back for more requests\n");
}
continue;
}
}
client.cpp
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP
void Usage(char *progname) {
fprintf(stderr, "Usage\n%s -p [protocol] -n [server] -e [endpoint] \
-l [iterations]\n",
progname);
fprintf(stderr, "Where:\n\tprotocol is one of TCP or UDP\n");
fprintf(stderr, "\tserver is the IP address or name of server\n");
fprintf(stderr, "\tendpoint is the port to listen on\n");
fprintf(stderr, "\titerations is the number of loops to execute\n");
fprintf(stderr, "\t(-l by itself makes client run in an infinite loop,");
fprintf(stderr, " Hit Ctrl-C to terminate it)\n");
fprintf(stderr, "Defaults are TCP , localhost and 5001\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {
char Buffer[128];
char *server_name = "localhost";
unsigned short port = DEFAULT_PORT;
int retval, loopflag = 0;
int i, loopcount, maxloop = -1;
unsigned int addr;
int socket_type = DEFAULT_PROTO;
struct sockaddr_in server;
struct hostent *hp;
WSADATA wsaData;
SOCKET conn_socket;
if (argc >1) {
for (i = 1; i <argc; i++) {
if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
switch (tolower(argv[i][1])) {
case 'p':
if (!_stricmp(argv[i + 1], "TCP"))
socket_type = SOCK_STREAM;
else if (!_stricmp(argv[i + 1], "UDP"))
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;
case 'n':
server_name = argv[++i];
break;
case 'e':
port = (USHORT)atoi(argv[++i]);
break;
case 'l':
loopflag = 1;
if (argv[i + 1]) {
if (argv[i + 1][0] != '-')
maxloop = atoi(argv[i + 1]);
}
else
maxloop = -1;
i++;
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
if ((retval = WSAStartup(0x202, &wsaData)) != 0) {
fprintf(stderr, "WSAStartup failed with error %d\n", retval);
WSACleanup();
return -1;
}
if (port == 0){
Usage(argv[0]);
}
//
// Attempt to detect if we should call gethostbyname() or
// gethostbyaddr()
if (isalpha(server_name[0])) { /* server address is a name */
hp = gethostbyname(server_name);
}
else { /* Convert nnn.nnn address to a usable one */
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr, 4, AF_INET);
}
if (hp == NULL) {
fprintf(stderr, "Client: Cannot resolve address [%s]: Error %d\n",
server_name, WSAGetLastError());
WSACleanup();
exit(1);
}
//
// Copy the resolved information into the sockaddr_in structure
//
memset(&server, 0, sizeof(server));
memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
server.sin_family = hp->h_addrtype;
server.sin_port = htons(port);
conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */
if (conn_socket <0) {
fprintf(stderr, "Client: Error Opening socket: Error %d\n",
WSAGetLastError());
WSACleanup();
return -1;
}
printf("Client connecting to: %s\n", hp->h_name);
if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr, "connect() failed: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
loopcount = 0;
while (1) {
sprintf_s(Buffer, sizeof(Buffer), "This is a small test message [number %d]", loopcount++);
retval = send(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("Sent Data [%s]\n", Buffer);
retval = recv(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
closesocket(conn_socket);
WSACleanup();
return -1;
}
if (retval == 0) {
printf("Server closed connection\n");
closesocket(conn_socket);
WSACleanup();
return -1;
}
printf("Received %d bytes, data [%s] from server\n", retval, Buffer);
if (!loopflag){
printf("Terminating connection\n");
break;
}
else {
if ((loopcount >= maxloop) && (maxloop >0))
break;
else
Sleep(2000);
}
}
closesocket(conn_socket);
WSACleanup();
}
In server.cpp where you're reading/writing the UDP socket:
else if (FD_ISSET(udp_socket, &SockSet))
{
retval = recvfrom(msgsock, Buffer, sizeof(Buffer), 0,
(struct sockaddr *)&from, &fromlen);
printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));
...
printf("Echoing same data back to client\n");
retval = sendto(msgsock, Buffer, sizeof(Buffer), 0,
(struct sockaddr *)&from, fromlen);
if (retval == SOCKET_ERROR) {
fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
}
printf("UDP server looping back for more requests\n");
}
You're using msgsock in your recv and send calls (as well as closesocket), which you use for the accepted TCP socket, instead of udp_socket.
Change msgsock to udp_socket in this block and it should work.
I'm using this code to connect to a server, but it is not waiting the 10 seconds I set to timeout. It returns immediately after failing to connect.
BOOL Connect(string server, int port, int timeout)
{
struct sockaddr_in RemoteHost;
TIMEVAL Timeout;
Timeout.tv_sec = timeout;
Timeout.tv_usec = 0;
int con_error = 0;
#ifdef W32
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
DEBUG(L"Failed to load Winsock!\n");
return FALSE;
}
#endif
//create socket if it is not already created
if (s == SOCKET_ERROR)
{
//Create socket
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == SOCKET_ERROR)
{
DEBUG(L"Could not create socket");
return FALSE;
}
}
//setup address structure
if (inet_addr(server.c_str()) == INADDR_NONE)
{
struct hostent *he;
//resolve the hostname, its not an ip address
if ((he = gethostbyname(server.c_str())) == NULL)
{
//gethostbyname failed
DEBUG(L"gethostbyname() - Failed to resolve hostname\n");
return FALSE;
}
}
else//plain ip address
{
RemoteHost.sin_addr.s_addr = inet_addr(server.c_str());
}
RemoteHost.sin_family = AF_INET;
RemoteHost.sin_port = htons(port);
//set the socket in non-blocking
unsigned long iMode = 1;
int iResult = ioctlsocket(s, FIONBIO, &iMode);
if (iResult != NO_ERROR)
{
DEBUGP(L"ioctlsocket failed with error: %ld\n", iResult);
return FALSE;
}
//Connect to remote server
if ((con_error=connect(s, (struct sockaddr *)&RemoteHost, sizeof(RemoteHost))) < 0)
{
if (con_error != EINPROGRESS)
{
DEBUG(L"connect() failed");
return FALSE;
}
}
// restart the socket mode
iMode = 0;
iResult = ioctlsocket(s, FIONBIO, &iMode);
if (iResult != NO_ERROR)
{
DEBUGP(L"ioctlsocket failed with error: %ld\n", iResult);
return FALSE;
}
fd_set Write, Err;
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(s, &Write);
FD_SET(s, &Err);
// check if the socket is ready
select(0, NULL, &Write, &Err, &Timeout);
if (FD_ISSET(s, &Write))
{
return TRUE;
}
return FALSE;
}
When the socket is not available on the target system, it may send back an ICMP message indicating that the socket is not open and attempt to connect was failed. In this case, winsock funcitons will return immediately - it's by design.
Use WSAGetLastError to find out why the call has failed. connect returns 0 on success or SOCKET_ERROR on failure.
You commented that WSAGetLastError returns WSAEWOULDBLOCK which states:
This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. It is a nonfatal error, and the operation should be retried later. It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect on a nonblocking SOCK_STREAM socket, since some time must elapse for the connection to be established.
So is expected behaviour on the non-blocking socket you have set up.