I'm following this tutorial that shows how to accept multiple connections without use of multi-threading.
The problem I run into is that the accept()
function always return SOCKET_ERROR
.
I want the server to accept multiple clients. I'd like if someone can point me to what I'm doing wrong.
Here's my server code:
#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <stdio.h>
#include <signal.h>
#include <conio.h>
#include <assert.h>
#include <Windows.h>
#include <iostream>
//sockets
#define CLIENT_CON 10
#define CLIENT_DIS 20
#define BF_SZ 100
#define MAX_CONS 5
SOCKET sock, clien;
int PR_CONS = 0;
struct _client
{
bool con; // Set true if a client is connected
sockaddr_in addr; // Client info like ip address
SOCKET cs; // Client socket
fd_set set; // used to check if there is data in the socket
int i; // any piece of additional info
};
_client client[10];
int accept(_client*);
int send(_client*, char*,int);
int recv(_client*, char*, int);
void Server_Status(int );
void char_message(char*);
void accept_clients();
void recv_client();
int main() {
//int res;
int i = 1;
int port = 5150;
SOCKET sock;
WSADATA ws;
printf("\t Echo Server (Multiple client support)\n");
sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_addr.S_un.S_addr = INADDR_ANY;
ser.sin_port = htons(port);
WSAStartup(MAKEWORD(2,2),&ws);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i,sizeof(i));
bind(sock,(SOCKADDR*)&ser, sizeof(ser));
listen(sock,5);
printf("listening \n");
unsigned long b= 1;
ioctlsocket(sock,FIONBIO,&b);
for(int i = 0; i < MAX_CONS; i++) {
client[i].con = false;
}
while(true) {
accept_clients();
recv_client();
}
}
int accept(_client* x) {
x->i = sizeof(sockaddr_in);
x->cs = accept(sock, (SOCKADDR*)&x->addr, &x->i);
if(x->cs != INVALID_SOCKET ) {
std::cout << x->cs << std::endl;
x->con = true;
FD_ZERO(&x->set);
FD_SET(x->cs,&x->set);
printf("accepted client");
return true;
}
//printf("failed to accept client");
return false;
}
int send(_client* x, char* buffer, int sz) {
x->i = send(x->cs, buffer, sz, 0);
if(x-> i == SOCKET_ERROR || x->i == 0 ) {
return false;
}
return true;
}
int recv(_client *x, char* buffer, int sz) {
if(FD_ISSET(x->cs,&x->set)) {
x->i = recv(x->cs,buffer,sz, 0);
if(x->i == 0) {
return false;
}
return true;
}
return false;
}
void accept_clients() {
for(int i = 0; i < MAX_CONS; i++) {
if(!client[i].con) {
if(accept(&client[i])) {
Server_Status(CLIENT_CON);
}
}
}
}
void Server_Status(int msg) {
if(msg == CLIENT_CON) {
PR_CONS++;
printf("client has connected");
}
else if(msg == CLIENT_DIS) {
PR_CONS--;
printf("client has disconnected");
}
else {
printf("we got unknown message");
}
}
void chat_message(char* s) {
int len = strlen(s);
for(int i = 0; i< MAX_CONS; i++) {
if(client[i].con) {
send(&client[i], s, len);
}
}
}
void recv_client() {
char buffer[BF_SZ];
for(int i = 0; i < MAX_CONS; i++) {
if(client[i].con) {
if(recv(&client[i],buffer, BF_SZ)) {
if(buffer[0] == '/') {
if(strcmp(buffer, "/server_bang") == 0) {
chat_message("** Hi**");
}
}
else {
chat_message(buffer);
}
}
}
}
}
The problem I run into is that the
accept()
function always returnSOCKET_ERROR
.
That is because you are passing it an invalid SOCKET
handle (had you bothered to check with WSAGetLastError()
after receiving SOCKET_ERROR
, it likely would have returned WSAENOTSOCK
).
The reason is because your accept()
wrapper function is calling Winsock's accept()
function with a global SOCKET
variable named sock
, but your main()
function never initializes that variable! It is instead initializing a local SOCKET
variable that is also named sock
. You need to either:
get rid of main()
's local sock
variable so main()
will then use the global sock
variable.
get rid of the global sock
variable, and have main()
pass its local sock
variable as an input parameter to your accept_clients()
function, which can then pass it as an input parameter to your accept()
function.