0% found this document useful (0 votes)
20 views

Tutorwinwsock

This document provides code for adding multiple client support to a Winsock server in C++. It uses ioctlsocket to make the server socket non-blocking and stores client sockets in a struct table. The code initializes Winsock, sets up the server socket, accepts new client connections in a loop, receives/sends data to clients in another loop, and closes connections gracefully. It also provides basic client code to connect to the server and send/receive data.

Uploaded by

Christian Muro
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

Tutorwinwsock

This document provides code for adding multiple client support to a Winsock server in C++. It uses ioctlsocket to make the server socket non-blocking and stores client sockets in a struct table. The code initializes Winsock, sets up the server socket, accepts new client connections in a loop, receives/sends data to clients in another loop, and closes connections gracefully. It also provides basic client code to connect to the server and send/receive data.

Uploaded by

Christian Muro
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Winsock Server adding Multiple clients support C++

This is very simple version to add multiple connection support to your server project. Here we are going to
use ioctlsocket to make it non blocking and small struct table for saving the client sockets. You should have
some sort of experience with winsockets or at least knowing how recv and send functions work. If you are
interested for getting to know winsockets better then you should head to microsoft developer pages, cause
pretty much everything else on the web is garbage and they seem to keep example codes updated on msdn
pages. Also you should know that the non blocking version is very cpu hungry cause of continuous polling
but with little tweak we can make it work nicely, especially with something small. Asynchronous Sockets are
for something bigger and stable, they kinda take non blocking sockets to next level. Hope this helps you to
find I/O strategy you are looking for.
This is the top of our code and almost all variables are there. And don't forget to link ws2_32 library.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <winsock2.h>

// Need to link with Ws2_32.lib


#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

using namespace std;

#define DEFAULT_PORT 27015


#define DEFAULT_BUFLEN 512
#define MAX_CLIENTS 50

char recvbuf[DEFAULT_BUFLEN] = "";


int len, receiveres, clients_connected = 0;
bool active = TRUE;

SOCKET server_socket = INVALID_SOCKET;


SOCKET client_fd;
sockaddr_in server;

//table for clients sockets


struct _clients_b {

bool connected;
SOCKET ss;

};

_clients_b clients[MAX_CLIENTS];

//function declarations

void start_server();
In this function we are setting up the server and i decided to put it all in one function, to make it
more easier to read.
So basically start_server function is made of:

WSAStartup
socket
setsockopt
bind
listen
ioctlsocket

int main() {

cout << "Server starting..." << endl;

//start the server and do basic tcp setup ------------------


start_server();

//the main loop


while (active) {

//start accepting clients ------------------------------


len = sizeof(server);
client_fd = accept(server_socket, (struct sockaddr*)& server, &len);

//our client is a real thing?


if (client_fd != INVALID_SOCKET) {

//save client socket into our struct table


clients[clients_connected].ss = client_fd;
clients[clients_connected].connected = TRUE;

//and of course we need a calculator too


clients_connected++;

cout << "New client: " << client_fd << endl;


}

//we might need to add some delays cause our code might be too fast
//commenting this function will eat your cpu like the hungriest dog
ever
//plus we don't need to loop that fast anyways
Sleep(1);

//receiving and sending data ---------------------------

//we have clients or no?


if (clients_connected > 0) {

//lets go through all our clients


for (int cc = 0; cc < clients_connected; cc++) {

memset(&recvbuf, 0, sizeof(recvbuf));

if (clients[cc].connected) {
//receive data
receiveres = recv(clients[cc].ss, recvbuf,
DEFAULT_BUFLEN, 0);

//and echo it back if we get any


if (receiveres > 0) {

Sleep(10);

cout << "Client data received: " << recvbuf


<< endl;
send(client_fd, recvbuf, strlen(recvbuf),
0);
}
//how to close connection
//this just for quick example
//so you are just getting rid off client's socket
data
else if (receiveres == 0 || strcmp(recvbuf,
"disconnect") == 0) {

cout << "Client disconnected." << endl;


clients[cc].connected = FALSE;
clients_connected--;
//delete [cc] clients;
}
}
}
}
}

//when we shut down our server


closesocket(server_socket);

// Clean up winsock
WSACleanup();

return 0;
}

void start_server() {
int wsaresult, i = 1;

WSADATA wsaData;

server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(DEFAULT_PORT);

// Initialize Winsock
wsaresult = WSAStartup(MAKEWORD(2, 2), &wsaData);

//if error
if (wsaresult != 0) {
printf("WSAStartup failed with error: %d\n", wsaresult);
}

// Create a SOCKET for connecting to server


server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (server_socket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
}

setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));

//Binding part
wsaresult = bind(server_socket, (sockaddr*)&server, sizeof(server));

if (wsaresult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
closesocket(server_socket);
WSACleanup();
}

// Setup the TCP listening socket


wsaresult = listen(server_socket, 5);

unsigned long b = 1;

//make it non blocking


ioctlsocket(server_socket, FIONBIO, &b);

if (wsaresult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(server_socket);
WSACleanup();
}

Client Code

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib


#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEFAULT_BUFLEN 512


#define DEFAULT_PORT "27015"
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char sendbuf[DEFAULT_BUFLEN] = "";
string sendbuf2;
char recvbuf[DEFAULT_BUFLEN] = "";
int iResult;
int recvbuflen = DEFAULT_BUFLEN;

// Validate the parameters


if (argc != 2) {
printf("usage: %s server-name\n", argv[0]);
//return 1;
}

// Initialize Winsock
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_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

// Resolve the server address and port


iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
//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();
//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();
//return 1;
}

int loopthis = 1;

while (loopthis == 1) {
cout << "Type to say: ";
getline(cin, sendbuf2);
cout << endl;

// Send an initial buffer


iResult = send(ConnectSocket, sendbuf2.c_str(),
(int)strlen(sendbuf2.c_str()), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
//return 1;
}

printf("Bytes Sent: %ld\n", iResult);

if (strcmp(sendbuf2.c_str(), "break") == 0) {
cout << "exiting...\n";
loopthis = 0;
break;
}
}

// shutdown the connection since no more data will be sent


iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
//return 1;
}

// Receive until the peer closes the connection


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);

// cleanup
closesocket(ConnectSocket);
WSACleanup();

int ok;
cin >> ok;
return 0;
}

You might also like