Skip to content

Instantly share code, notes, and snippets.

@redatawfik
Created June 12, 2020 03:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save redatawfik/78caa1d6e06ebc0b94125c9b47183003 to your computer and use it in GitHub Desktop.
Save redatawfik/78caa1d6e06ebc0b94125c9b47183003 to your computer and use it in GitHub Desktop.
Server implementation of client-server chat using Winsock
#include <winsock2.h>
#include <iostream>
struct CLIENT_INFO {
SOCKET hClientSocket;
struct sockaddr_in clientAddr;
};
char szServerIPAddr[] = "192.168.1.4"; // Put here the IP address of the server
int nServerPort = 5050; // The server port that will be used by
// clients to talk with the server
bool InitWinSock2_0();
BOOL WINAPI ClientThread(LPVOID lpData);
using namespace std;
int main() {
if (!InitWinSock2_0()) {
cout << "Unable to Initialize Windows Socket environment" << WSAGetLastError() << endl;
return -1;
}
SOCKET hServerSocket;
hServerSocket = socket(
AF_INET, // The address family. AF_INET specifies TCP/IP
SOCK_STREAM, // Protocol type. SOCK_STREM specified TCP
0 // Protoco Name. Should be 0 for AF_INET address family
);
if (hServerSocket == INVALID_SOCKET) {
cout << "Unable to create Server socket" << endl;
// Cleanup the environment initialized by WSAStartup()
WSACleanup();
return -1;
}
// Create the structure describing various Server parameters
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET; // The address family. MUST be AF_INET
serverAddr.sin_addr.s_addr = inet_addr(szServerIPAddr);
serverAddr.sin_port = htons(nServerPort);
// Bind the Server socket to the address & port
if (bind(hServerSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
cout << "Unable to bind to " << szServerIPAddr << " port " << nServerPort << endl;
// Free the socket and cleanup the environment initialized by WSAStartup()
closesocket(hServerSocket);
WSACleanup();
return -1;
}
// Put the Server socket in listen state so that it can wait for client connections
if (listen(hServerSocket, SOMAXCONN) == SOCKET_ERROR) {
cout << "Unable to put server in listen state" << endl;
// Free the socket and cleanup the environment initialized by WSAStartup()
closesocket(hServerSocket);
WSACleanup();
return -1;
}
// Start the infinite loop
while (true) {
// As the socket is in listen mode there is a connection request pending.
// Calling accept( ) will succeed and return the socket for the request.
SOCKET hClientSocket;
struct sockaddr_in clientAddr;
int nSize = sizeof(clientAddr);
hClientSocket = accept(hServerSocket, (struct sockaddr *) &clientAddr, &nSize);
if (hClientSocket == INVALID_SOCKET) {
cout << "accept( ) failed" << endl;
} else {
HANDLE hClientThread;
struct CLIENT_INFO clientInfo;
DWORD dwThreadId;
clientInfo.clientAddr = clientAddr;
clientInfo.hClientSocket = hClientSocket;
cout << "Client connected from " << inet_ntoa(clientAddr.sin_addr) << endl;
// Start the client thread
hClientThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) ClientThread,
(LPVOID) &clientInfo, 0, &dwThreadId);
if (hClientThread == NULL) {
cout << "Unable to create client thread" << endl;
} else {
CloseHandle(hClientThread);
}
}
}
closesocket(hServerSocket);
WSACleanup();
return 0;
}
bool InitWinSock2_0() {
WSADATA wsaData;
WORD wVersion = MAKEWORD(2, 0);
return !WSAStartup(wVersion, &wsaData);
}
BOOL WINAPI ClientThread(LPVOID lpData) {
CLIENT_INFO *pClientInfo = (CLIENT_INFO *) lpData;
char szBuffer[1024];
int nLength;
while (1) {
nLength = recv(pClientInfo->hClientSocket, szBuffer, sizeof(szBuffer), 0);
if (nLength > 0) {
szBuffer[nLength] = '\0';
cout << "Received " << szBuffer << " from " << inet_ntoa(pClientInfo->clientAddr.sin_addr) << endl;
// Convert the string to upper case and send it back, if its not QUIT
strupr(szBuffer);
if (strcmp(szBuffer, "QUIT") == 0) {
closesocket(pClientInfo->hClientSocket);
return TRUE;
}
// send( ) may not be able to send the complete data in one go.
// So try sending the data in multiple requests
int nCntSend = 0;
char *pBuffer = szBuffer;
while ((nCntSend = send(pClientInfo->hClientSocket, pBuffer, nLength, 0) != nLength)) {
if (nCntSend == -1) {
cout << "Error sending the data to " << inet_ntoa(pClientInfo->clientAddr.sin_addr) << endl;
break;
}
if (nCntSend == nLength)
break;
pBuffer += nCntSend;
nLength -= nCntSend;
}
} else {
cout << "Error reading the data from " << inet_ntoa(pClientInfo->clientAddr.sin_addr) << endl;
}
}
return TRUE;
}
@MohamedKari
Copy link

MohamedKari commented Jan 17, 2022

Hi, Thanks a lot for sharing!

Shouldn't it be

nLength = recv(pClientInfo->hClientSocket, szBuffer, sizeof(szBuffer) - 1, 0);

(reducing the number of bytes to read by -1) in line 115 (https://gist.github.com/redatawfik/78caa1d6e06ebc0b94125c9b47183003#file-server-cpp-L115)?

Wouldn't otherwise szBuffer[nLength] = '\0' (line 117) throw, if the full buffer has been filled?

Thanks and best,
Mo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment