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.
Related
I have made Mutlti-Client sever that can receive and send messages to the sever and the sever can send back the messages to clients but the problem I'm having is client A will not be able to receive the message from client B unless Client A sends a message I want the clients to receive messages anytime I also want to be to type commands on the sever without stopping the flow of sending to clients and receiving message from clients
I have tried moving the std::getline(std::cin, ClientInput); to different place in the code so clients could be able to see message but I have notice in the code the while loop does not continue because of it is there a way to get user input with out stopping the loop so can send and receive messages
This the Client code
int Client::OnCreate()
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL, *ptr = NULL, hints;
char sendbuf[] = "this is a test";
std::vector<SOCKET> ConnectedUser;
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
system("pause");
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
system("pause");
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
system("pause");
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
system("pause");
return 1;
}
// Send an initial buffer
std::string ClientInput;
std::cout << "please send a message " << std::endl;
std::getline(std::cin, ClientInput);
do {
if (ClientInput.size() > 0)
{
//send user input to sever
iResult = send(ConnectSocket, ClientInput.c_str(), ClientInput.size(), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
system("pause");
return 1;
}
printf("Bytes Sent: %d\n", iResult);
if (iResult != SOCKET_ERROR)
{
//receive user input from sever
int iUserResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iUserResult > 0)
{
std::cout << "Client receive this message from sever \t" << std::string(recvbuf, 0, iResult) << std::endl;
printf("Bytes received: %d\n", iUserResult);
}
}
//will disconnect from the sever
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
system("pause");
}
//will disconnect from the sever if user types in logoff
if (ClientInput == "logoff")
{
closesocket(ConnectSocket);
WSACleanup();
printf("Connection closing goodbye sever\n");
system("pause");
}
//close connection if the no user input
if (iResult == 0) {
printf("Connection closed\n");
iResult = shutdown(ConnectSocket, SD_SEND);
}
}
std::getline(std::cin, ClientInput);
} while (ClientInput.size() > 0);
// cleanup
closesocket(ConnectSocket);
system("pause");
WSACleanup();
return 0;
}```
This is the sever code
std::vector<SOCKET> ConnectedUser;
std::vector<int> UserInt;
unsigned __stdcall ClientSession(void *data)
{
char recvbuf[DEFAULT_BUFLEN];
int recvbufleng = DEFAULT_BUFLEN;
int iResult;
int iSendResult;
SOCKET ClientSocket = (SOCKET)data;
struct addrinfo *result = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
do
{
iResult = recv(ClientSocket, recvbuf, recvbufleng, 0);
///iResult = recv(ClientSocket, recvbuf, sizeof(Player), 0);
std::cout << iResult << std::endl;
if (iResult > 0) {
for (int i = 0; i < ConnectedUser.size(); i++) {
std::cout << "send message to "<< ConnectedUser[i] << std::endl;
//iSendResult = send(ClientSocket, recvbuf, iResult, 0);
iSendResult = send(ConnectedUser[i], recvbuf, iResult, 0);
//ConnectedUser.clear();
//iSendResult = sendto(ConnectedUser[i], recvbuf, iResult, 0, (sockaddr*)&hints, sizeof(hints));
}
std::cout << "ClientSocket" << ClientSocket << std::endl;
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d \n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Received Message %.*s\n", iResult, recvbuf);
}
else if (iResult == 0)
{
printf("connection closing.... \n");
std::cout << "user logged off" << ClientSocket << std::endl;
}
else
{
printf("recv failed with error: %d \n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d \n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
closesocket(ClientSocket);
}
int Sever::OnCreate()
{
WSADATA wsaData;
int iResult;
SOCKET ClientSocket = INVALID_SOCKET;
//send to
char recvbuf[DEFAULT_BUFLEN];
int recvbufleng = DEFAULT_BUFLEN;
int iSendResult;
struct addrinfo *result = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
//create the winsocket
if (iResult != 0) {
printf("WSAStartup failed: %d\n, iResult");
return 1;
}
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ListenSocket = INVALID_SOCKET;
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("error at socket(): %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind(ListenSocket, result->ai_addr, int(result->ai_addrlen));
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d \n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
printf("Listen failed with error: %d \n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
FD_SET(ListenSocket, &master);
fd_set copy = master;
int socketCount = select(0, ©, nullptr, nullptr, nullptr);
std::cout << " socketCount "<< socketCount << std::endl;
//// Send an initial buffer
//if (socketCount == 0) {
// std::string SeverInput;
// std::cout << "input Server command" << std::endl;
// std::getline(std::cin, SeverInput);
//
// if (SeverInput == "exit")
// {
// closesocket(ClientSocket);
// WSACleanup();
// printf("Connection closing goodbye sever\n");
// }
//}
for (int i = 0; i < socketCount; i++)
{
SOCKET sock = copy.fd_array[i];
if (sock == ListenSocket)
{
//// Accept a new connection
while ((ClientSocket = accept(ListenSocket, NULL, NULL))) {
if (ClientSocket == INVALID_SOCKET) {
printf("Accept failed with error: %d \n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
/* Messtotal.push_back(ClientSocket + "\n");*/
// Add the new connection to the list of connected clients
FD_SET(ClientSocket, &master);
ConnectedUser.push_back(ClientSocket);
std::cout << "client:" << ClientSocket <<" has arrived on sever" <<std::endl;
// Create a new thread for the accepted client (also pass the accepted client socket).
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID);
}
}
}
WSACleanup();
printf("Server shutting down ");
return 0;
```}
Moving the std::getline(std::cin, ClientInput) anywhere within loop in client code will not help you becase getline() is a blocking call. In this case you should use threads in client code.
You need to create a new thread in client code with while loop. In this thread you will incoming messages from another client.
Main thread in client code will handle user input from getline() and sending messages via send function within while loop.
For example in your client code you can create thread like this :
m_hTrhead = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)processMessage, (LPVOID)ConnectSocket, CREATE_SUSPENDED, 0);
if (m_hTrhead == NULL)
{
printf("Failed to create thread for receiving messages , error code : %ld \n", GetLastError());
return false;
}
And thread will will process messages in function processMessage like this :
DWORD WINAPI Socket::processMessage(LPVOID lpParam)
{
SOCKET ConnectSocket= reinterpret_cast <SOCKET>(lpParam);
while (WSAGetLastError() != WSAECONNRESET)
{
int iUserResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iUserResult > 0)
{
std::cout << "Client receive this message from sever \t" << std::string(recvbuf, 0, iResult) << std::endl;
printf("Bytes received: %d\n", iUserResult);
}
}
}
Be aware that non- blocking sockets exists also (So thread will not stop at recv or send function). Function names for non-blocking socket are the same but you must set the socket itself to non-blocking.
u_long mode = 1; // enable non-blocking socket
ioctlsocket(sock, FIONBIO, &mode);
You can read about this more here
I'm trying to create simple C++ server-client application, which allows multiple users to connect to server. The problem is that after creating new thread for each client, recv function started to crash clients app.
Here is my code for creating new thread for each client connected:
while (ClientSocket = accept(ListenSocket, 0, 0)) {
if (ClientSocket == INVALID_SOCKET) {
printf("\ninvalid client socket", GetLastError());
continue;
}
unsigned threadID;
HANDLE myhandleB = (HANDLE) _beginthreadex(NULL, 0, &Server::receiveMessageThread, (void *) &ClientSocket, 0,
&threadID);
}
And here is a method which is trying to receive a messages from server:
void waitForMessage() {
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
}
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
}
After calling:
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
client app stops responding.
All of your client threads are receiving a pointer to the same SOCKET variable, so they are going to trample on each other. You need to pass a copy of the SOCKET to each thread instead.
You are also leaking the HANDLE that _beginthreadex() returns if successful, and leaking the accepted SOCKET if failed.
Try this instead:
// make sure this is declared as 'static' in the 'Server' class declaration...
unsigned __stdcall Server::receiveMessageThread(void *arg)
{
SOCKET ClientSocket = (SOCKET) arg;
...
closesocket(ClientSocket);
return 0;
}
...
while (true)
{
ClientSocket = accept(ListenSocket, 0, 0);
if (ClientSocket == INVALID_SOCKET)
{
printf("\ninvalid client socket", GetLastError());
continue;
}
unsigned threadID;
HANDLE myhandleB = (HANDLE) _beginthreadex(NULL, 0, &Server::receiveMessageThread, (void *) ClientSocket, 0, &threadID);
if (myhandleB)
CloseHandle(myhandleB);
else
closesocket(ClientSocket);
}
I made a window using the Win32 API and it needs to enter a message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
How do I create a socket server and start receiving clients, if my main thread is processing UI messages?
I tried putting all of the server code in a thread using CreateThread() from WinMain(), but it just crashes with an error:
Exception thrown at 0x00000000 in test.exe: 0xC0000005: Access violation executing location 0x00000000.
Here is the thread code:
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
// Initialize Winsock
WSADATA wsaData;
auto iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return EXIT_FAILURE;
}
addrinfo hints;
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
PADDRINFOA pAddrInfo = nullptr;
iResult = getaddrinfo(nullptr, PORT, &hints, &pAddrInfo);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return EXIT_FAILURE;
}
while (true) {
// Create a SOCKET for connecting to server
auto ListenSocket = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(pAddrInfo);
WSACleanup();
return EXIT_FAILURE;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, pAddrInfo->ai_addr, static_cast<int>(pAddrInfo->ai_addrlen));
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(pAddrInfo);
closesocket(ListenSocket);
WSACleanup();
return EXIT_FAILURE;
}
freeaddrinfo(pAddrInfo);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return EXIT_FAILURE;
}
// Accept a client socket
auto ClientSocket = accept(ListenSocket, nullptr, nullptr);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return EXIT_FAILURE;
}
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
for (;;)
{
char recvbuf[1] = { 0 };
auto cbLen = recv(ClientSocket, recvbuf, sizeof(recvbuf), 0);
if (cbLen > 0) {
if (recvbuf[0] == 0xDA)
{
Hide();
}
continue;
}
else if (cbLen == 0) {
printf("Connection closing...\n");
break;
}
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return EXIT_FAILURE;
}
}
// shutdown receive operations since we're done
iResult = shutdown(ClientSocket, SD_RECEIVE);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return EXIT_FAILURE;
}
// cleanup
closesocket(ClientSocket);
}
WSACleanup();
return 0;
}
This is a very confusing question as it asks one question in the title, but the content addresses a different problem (threads crashing).
To address the primary question: Microsoft did add a way to handle socket communications in a GUI thread friendly way: WSAAsyncSelect. This will send socket events as messages to your applications message queue - typically an invisible window is created to handle the messages.
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.
I have code (my c++ socket server) but I don't know How can I always open. My server will close. when It already send to client It will close itself. But I want it to wait others client and never closed. How can I do it ? Oh I use multi-threaded too.
please,Help me.
and here is my code
int main(void)
{
HANDLE hThread[3];
DWORD dwID[3];
DWORD dwRetVal = 0;
hThread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadTwo,NULL,0,&dwID[0]);
dwRetVal = WaitForMultipleObjects(3, hThread, TRUE, INFINITE);
CloseHandle(hThread[0]);
return 0;
}
long WINAPI ThreadTwo(long lParam)
{
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET,
ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
hints;
char recvbuf[DEFAULT_BUFLEN];
int iResult, iSendResult;
int recvbuflen = DEFAULT_BUFLEN;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
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;
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Waiting for client\n");
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Client acctped.\n");
closesocket(ListenSocket);
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
recvbuf[iResult] = '\0';
printf(recvbuf);
char* testsend = "222 333\n444 555\n666 777" ;
iSendResult = send( ClientSocket, testsend , strlen(testsend)+1 , 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
system("pause");
closesocket(ClientSocket);
WSACleanup();
return 0;
}
thank again.
You have to use a loop for that :)
Basically, the server main code must be in a loop, that will go forever ... while you do not stop it.
you should have :
// That's close to pseudo code :)
while(notStoppedByMaster)
{
// [...]
ClientSocket = accept(ListenSocket, NULL, NULL);
handleRequest(ClientSocket);
}
// close the listen socket here
The handleRequest should handle the request in another thread. Be attentive to synchronization :)
my2c
Firstly, it looks like you are creating a console application. If I were you I would create a WIN32 application instead. This means you'll have a GUI but more importantly, a message loop. The message loop allows you to use Asynchronous sockets, it takes a little more understanding but it gives much better and cleaner results.
Read about WSAAsyncSelect:
http://msdn.microsoft.com/en-us/library/ms741540%28VS.85%29.aspx
Also read socket tutorial:
http://msdn.microsoft.com/en-us/library/ms738545%28v=VS.85%29.aspx
Secondly, if you HAVE to use synchronous (blocking) sockets, yes you'll have to be running each on its own thread. You Need to have a loop in which you wait for connections, and then have client sockets like you did, being assigned from your accept(). Then let the client sockets run on their own thread.
Also you are closing your listensocket for some reason in the middle of the code.