Only first few multithreaded clients can read response from socket - c

I am building a client-server program in C using sockets. Both my client and my server use a fixed number of threads to operate. I tested with very few client and server threads at first (5 and 3) and everything seemed to work fine. But now I tried to up the number of client threads to 500 (while the number of server thread stays at 3), but everything breaks. The first hundred or so client can send their request and receive a response, but the others don't receive anything from the server.
I'm working on a Debian Windows Subsystem if that changes anything.
I have also tried upping the number of server thread to 300 but the problem still happens.
Here is my (very) simplified code.
Client thread
int client_socket= socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2018);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
connect(client_socket, (struct sockaddr *) &addr, sizeof(addr));
int response;
int cid = 1;
send(client_socket, &cid, sizeof(int), 0);
int len = read_socket(socket, &response, sizeof(int), 1000);
if (len == 0) {
printf("No response");
} else {
printf("Response");
}
close(client_socket);
Server thread
int socket_fd, cid, len;
while (1)
{
socket_fd =
accept(socket_fd, (struct sockaddr *)&thread_addr, &socket_len);
if (socket_fd> 0) {
int cid;
int len = read_socket(socket_fd, &cid, sizeof(cid), 1000);
if (len == 0) {
printf("Nothing");
}
send(socket_fd, &cid, sizeof(int),0);
close(socket_fd);
}
}
And here is my helper function read_socket()
ssize_t read_socket(int sockfd, void *buf, size_t obj_sz, int timeout) {
int ret;
int len = 0;
struct pollfd fds[1];
fds->fd = sockfd;
fds->events = POLLIN;
fds->revents = 0;
do {
// wait for data or timeout
ret = poll(fds, 1, timeout);
if (ret > 0) {
if (fds->revents & POLLIN) {
ret = recv(sockfd, (char*)buf + len, obj_sz - len, 0);
if (ret < 0) {
// abort connection
perror("recv()");
return -1;
}
len += ret;
}
} else {
// TCP error or timeout
if (ret < 0) {
perror("poll()");
}
break;
}
} while (ret != 0 && len < obj_sz);
return ret;
}
Like I said, some client can complete their execution with no problem, but a lot of them don't receive a response from the server.

Related

How to know if a network error is fatal or not in UDP server written in C?

In the code below:
static int recv_commands(uint16_t port) {
int s, rc;
struct sockaddr_in svr;
char buf[1024];
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
rc = errno;
goto quit;
}
svr.sin_family = AF_INET;
svr.sin_port = port;
svr.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *)&svr, sizeof(svr)) < 0) {
rc = errno;
goto quit;
}
while(1) {
if (recv(s, buf, sizeof(buf), 0) < 0) {
rc = errno;
break;
}
//TODO: process buf...
}
quit:
close(s);
return rc;
}
I would like to know what are the possible errors that could happen in recv(s, buf, sizeof(buf), 0)? If error happens, shall I continue or break the while loop?
i.e. will the error be fatal so that when an error happen, further recv() is not feasible?

C Proxy crashing

Im writing a program which connects to a browser and sends the http request from the browser to a server, and then sends the response back to the browser, which loads the page with some of the content. My program sends things successfully and loads pages, but does not run continuously and will crash after a random amount of time- sometimes 10 seconds of running sometimes 1 minute. I want this proxy to be able to run forever. Below is how I have structured my code. I have included the recv and write section which I think is causing my errors in full. I am pretty new to socket programming and c In general and looking for some tips on my structure and anything I may have missed.
int main(int argc, char *argv[])
{
char ip[40]
char *host = argv[1];
char *port_s = argv[2];
int err;
int socket_browser, socket_newBrowser, c;
struct sockaddr_in server, client;
int n;
socket_browser= socket(AF_INET, SOCK_STREAM, 0);
if (socket_browser < 0)
{
printf("Could not create socket");
}
if (err = bind(socket_browser , (struct sockaddr *)&server, sizeof(server)) != 0)
{
resourceError(err, "bind");
return 1;
}
if (err = listen(socket_browser , 3) != 0)
{
resourceError(err, "listen");
}
while (1){
c = sizeof(struct sockaddr_in);
server_socket= accept(socket_browser, (struct sockaddr *)&client, (socklen_t *)&c);
char buf[256];
int n;
n = recv(socket_newBrowser, buf, 256, 0);
if (n < 0){
resourceError(n,"recv");
}
int server_socket;
struct sockaddr_in server2;
server_socket= socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
{
resourceError(server_socket, "serverSocket");
}
server2.sin_addr.s_addr = inet_addr(ip);
server2.sin_family = AF_INET;
server2.sin_port = htons(80);
connect(server_socket, (struct sockaddr *)&server2, sizeof(server2))
send(server_socket, buf, strlen(buf), 0);
char reply[256];
int bytes_reply = 0;
do
{
bytes_reply = recv(server_socket, reply, sizeof(reply), 0);
// Need to check for double enter as this currently does not work in telnet
if (bytes_reply == -1)
{
perror("Recv error");
}
else
{
write(server_socket, reply, bytes_reply);
}
} while (bytes_reply > 0);
printf("connections closed");
}
return 0;
}
I think your problem (or at least a problem) is:
n = recv(socket_newBrowser, buf, 256, 0);
/*versus*/
send(server_socket, buf, strlen(buf), 0);
buf is not null-terminated, you should have used the n value returned from recv instead of strlen.

How to use IO multiplexing technology to improve server concurrency performance?

I want to make a server software similar to Apache on windows platforms.
. The client sends data to the specified server port and the server responds accordingly. In order to improve the client access speed, I want to use "select" to improve the performance of the server, but there are many problems in the use process.
Here is my code;
Function "create_server"
This function is used to create the server Socket and set it to non-blocking.
int create_server(char*ip_address,int port) {
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
int server_socket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
int ret = -1;
struct sockaddr_in addr;
if (server_socket == -1) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr= INADDR_ANY;
ret = bind(server_socket,(LPSOCKADDR)&addr,sizeof(addr));
if (ret == -1) {
perror("bind error!");
return -2;
}
listen(server_socket,5);
SetBlock(server_socket, 0);
return server_socket;}
Function "SetBlock"
This function is used to change the socket blocking mode.
int SetBlock(int sock, int isblock){
int re = 0;
unsigned long ul = 0;
if (!isblock) ul = 1;
re = ioctlsocket(sock, FIONBIO, (unsigned long*)& ul);
if (re != 0) return 0;
return 1;
}
Function "main"
int main() {
int s = create_server("127.0.0.1",6666);
int client_socket = -1;
struct sockaddr_in clientaddr;
int addrlen = sizeof(clientaddr);
char buf[1025];
int buffersize=1,result=0;
int isread = 0;
fd_set server;
struct timeval timeout;
int fd = 0;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
FD_ZERO(&server);
FD_SET(s, &server);
while (1) {
result = select(FD_SETSIZE, &server, NULL, NULL, NULL);
if (result < 1) {
perror("error!");
exit(1);
}
if (FD_ISSET(s, &server)) {
//if server can be readable and written do this
client_socket = accept(s, (struct sockaddr*) & clientaddr, &addrlen);
while (buffersize > 0) {
buffersize = recv(client_socket, buf, 1024, 0);
buf[buffersize] = '\0';
printf("%s", buf);
if (buffersize < 1024) {
break;
}
}
buffersize = 1;
}
}
return 0;}
As you know, TCP takes some time to establish a connection. I want to use the "select" function to reduce the setup time of multi-client connections. I think the function "accept" is the process of establishing connection between client and server, but how to use IO multiplexing in this process, please help me.
the use of select() will delay all client connections to the server.
suggest a sequence similar to:
create a thread pool
create a sockaddr_in
sock_t serverSock = socket()
bind()
listen()
while( 1 )
{
sock_t clientSock = accept( serverSock, ... )
pass clientSock to available thread and mark thread as 'busy'
}
That way, the communication with a client does not 'hang' on a select(), nor a accept()
in each thread:
while(1)
{
wait until thread marked as 'busy'
sock_t mySocket = passedSocket
perform all communication with the specific client
close( mySocket );
mark thread as 'idle'
}

Winsock Server using WinAPI Thread reset first connection

I have written a Server using WINAPI with CreateThread() Method. The first connection request always dies. All the following requests/threads are working as expected. I have no idea why so i hope someone could tell me. Here is a working example illustrating the issue.
DWORD WINAPI process_thread(LPVOID lpParam) {
SOCKET current_client = (SOCKET)lpParam;
char buf[1024];
int res;
while(1) {
res = recv(current_client, buf, strlen(buf), 0);
if(res>0) {
buf[res] = '\0';
send(current_client, buf, strlen(buf), 0);
}
}
}
int main() {
SOCKET sock;
DWORD thread;
WSADATA wsaData;
SOCKADDR_IN server;
WSAStartup(0x102,&wsaData);
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=htons(123);
sock=socket(AF_INET,SOCK_STREAM,0);
bind(sock,(SOCKADDR*)&server,sizeof(server));
listen(sock,5);
SOCKET client;
SOCKADDR_IN from;
int fromlen = sizeof(from);
while(1) {
client = accept(sock,(struct SOCKADDR*)&from,&fromlen);
CreateThread(NULL, 0,process_thread,(LPVOID)client, 0, &thread);
}
closesocket(sock);
WSACleanup();
return 0;
}
You are misusing strlen() inside your thread code.
When calling recv(), you need to specify the full size of your buffer. strlen() is not the right way to get that value. Use sizeof() instead.
Then, when recv() exits, its return value tells you exactly know how many bytes in the buffer are valid. Again, strlen() is not the right way to get that value.
Also, you don't need to null-terminate the buffer just to pass it to send(). Since you are told how many bytes are in the buffer, just send that many bytes.
Also, your threads are not terminating, or closing their sockets, when clients disconnect from the server.
Also, your main() is leaking thread handles, and not doing any kind of error handling at all.
Try something more like this instead:
bool sendAll(SOCKET sock, void *buf, int buflen)
{
char *ptr = (char*) buf;
int sent;
while (buflen > 0) {
sent = send(sock, ptr, buflen, 0);
if (sent == SOCKET_ERROR) {
return false;
}
ptr += sent;
buflen -= sent;
}
return true;
}
DWORD WINAPI process_thread(LPVOID lpParam) {
SOCKET client = (SOCKET) lpParam;
char buf[1024], *ptr;
int recvd;
do {
recvd = recv(client, buf, sizeof(buf), 0);
if (recvd <= 0) {
break;
}
if (!sendAll(client, buf, recvd)) {
break;
}
}
while (true);
closesocket(client);
return 0;
}
int main() {
WSADATA wsaData;
SOCKET server, client;
SOCKADDR_IN serveraddr;
SOCKADDR_IN clientaddr;
int res, clientaddrlen;
HANDLE hThread;
DWORD threadID;
res = WSAStartup(MAKEWORD(2, 1), &wsaData);
if (res != 0) {
return 1;
}
ZeroMemory(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(123);
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET) {
WSACleanup();
return 1;
}
res = bind(server, (SOCKADDR*) &serveraddr, sizeof(serveraddr));
if (res == SOCKET_ERROR) {
closesocket(server);
WSACleanup();
return 1;
}
res = listen(server, 5);
if (res == SOCKET_ERROR) {
closesocket(server);
WSACleanup();
return 1;
}
do {
clientaddrlen = sizeof(clientaddr);
client = accept(server, (SOCKADDR*) &clientaddr, &clientaddrlen);
if (client == INVALID_SOCKET) {
closesocket(server);
WSACleanup();
return 1;
}
hThread = CreateThread(NULL, 0, process_thread, (LPVOID) client, 0, &threadID);
if (hThread)
CloseHandle(hThread);
else
closesocket(client);
}
while (true);
closesocket(server);
WSACleanup();
return 0;
}

C, socket programming: Connecting multiple clients to server using select()

I'm trying to make a server that can be connected to by multiple clients. Here's my code so far:
Client:
int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
Server:
int main(int argc, char **argv) {
fd_set fds, readfds;
int i, clientaddrlen;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
struct sockaddr_in serveraddr, clientaddr;
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(6782);
if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,
sizeof(struct sockaddr_in)))
perror("Bind");
if (-1 == listen(serversock, SOMAXCONN))
perror("Listen");
FD_ZERO(&fds);
FD_SET(serversock, &fds);
while(1) {
readfds = fds;
rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (rc == -1) {
perror("Select");
break;
}
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &readfds)) {
if (i == serversock) {
if (numsocks < maxsocks) {
clientsock[numsocks] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
if (clientsock[numsocks] == -1) perror("Accept");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
} else {
printf("Ran out of socket space.\n");
}
} else {
int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
}
}
}
}
close(serversock);
return 0;
}
As soon as a client connects and sends its first message, the server just runs in an infinite loop, and spits out garbage from the message array. recv doesn't seem to receive anything. Can anyone see where i go wrong?
Two issues in your code:
You should do recv(i, ...) instead of recv(clientsock[i], ...)
After that you do not check if recv() failed, and therefore printf() prints out the uninitialised buffer message, hence the garbage in the output
You need to check for limit <= 0 in your read loop, before you call read.
In the while loop for the server, change the code to do recv(i) instead of recv(clientsocks[i]). I have implemented this code and it works with this change.
I replaced the else with the below and it works
} else {
/* int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
memset ( &message[index] , 0, sizeof ( message [index] ) );
while ((in = recv(i, &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
*/
bzero(buf, sizeof(buf));
if ((rval = read(i, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
}
1) It is a good practice to use PF_INET(protocol family) rather than
AF_INET(address family) during the Socket creation .
2) within the while(1) loop
each time it is advisable to make your readfds empty by using FD_ZERO(&readfds).
in the recv() call you should use i rather than clientsocks[i]
you have to check return value of recv is negative(which indicating error in reading) if that is the case you do not have to print the message.
during printing the message make sure the stdout/server is ready for writing anything to it which you can do it by using writefds (3rd argument of select).

Resources