Не могу победить TIME_WAIT, как закрывать сокеты?
По определённым причинам, необходимо реализовать свой хттп-сервер, не требовательный к ресурсам (т.е. запуск нового thread на новый коннект - вполне ничо так решение). Всё отлично, кроме одного: мат. ожидание нагрузки - 2 запроса в секунду. Но при этом, закрытые сокеты остаются висеть в памяти в состоянии TIME_WAIT, и где-то через 5-10 минут лимит заканчивается, и на очередном вызове (предположительно) accept основной поток завершается, и вёб-сервер накрывается медным тазом, вместе со всеми своими обязанностями. Спрашивается, как решить эту неприятную ситуацию, если вот апач вполне с ней справляется? Хотя, этот кажется процесс новый запускает каждый раз... но всё равно, форки мне не помогли. В интернете была информацию по этой проблеме, но решения найти не смог. Привожу код сервера. Для исключения возможности проблем с синхронизацией, привожу полностью однопоточный код (который легко возвращается в многопоточный). Открывается на 4747 порту.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include <pthread.h>
#define CONNMAX 1000
#define BYTES 1024
#define MAX_PATH 260
char ROOT[MAX_PATH];
int listenfd;//, clients[CONNMAX];
void start_listen(char *port)
{
struct addrinfo hints, *res, *p;
// getaddrinfo for host
memset (&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo( NULL, port, &hints, &res) != 0)
{
perror ("getaddrinfo() error");
exit(1);
}
// socket and bind
for (p = res; p!=NULL; p=p->ai_next)
{
listenfd = socket (p->ai_family, p->ai_socktype, 0);
if (listenfd == -1) continue;
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break;
}
if (p==NULL)
{
perror ("socket() or bind()");
exit(1);
}
freeaddrinfo(res);
// listen for incoming connections
if ( listen (listenfd, 1000000) != 0 )
{
perror("listen() error");
exit(1);
}
}
int init_server()
{
char c;
//Default Values PATH = ~/ and PORT=4747
char PORT[6];
strcpy(PORT,"4747");
strcpy(ROOT, getenv("PWD"));
strcat(ROOT, "/web");
printf("%sWeb panel runned at port %s%s%s\n", "\033[92m", "\033[36m", PORT, "\033[0m");
// printf("Server started at port no. %s%s%s with root directory as %s%s%s\n","\033[92m",PORT,"\033[0m","\033[92m",ROOT,"\033[0m");
// Setting all elements to -1: signifies there is no client connected
int i;
start_listen(PORT);
}
//client connection
void * respond(void * sock_v)
{
int sock = (int) sock_v;
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fd, bytes_read;
memset( (void*)mesg, (int)'\0', 99999 );
rcvd=recv(sock, mesg, 99999, 0);
if (rcvd<0) // receive error
fprintf(stderr,("recv() error\n"));
else if (rcvd==0) // receive socket closed
fprintf(stderr,"Client disconnected upexpectedly.\n");
else // message received
{
//printf("%s", mesg);
reqline[0] = strtok (mesg, " \t\n");
if ( strncmp(reqline[0], "GET\0", 4)==0 )
{
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0 && strncmp( reqline[2], "HTTP/1.1", 8)!=0 )
{
write(sock, "HTTP/1.0 400 Bad Request\n", 25);
}
else
{
if ( strncmp(reqline[1], "/\0", 2)==0 )
reqline[1] = (char*)"/status.html"; //Because if no file is specified, index.html will be opened by default (like it happens in APACHE...
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
//printf("file: %s\n", path);
static int resp_num = 0;
char buff[100];
sprintf(buff, "Responsed %d times", ++resp_num);
send(sock, "HTTP/1.0 200 OK\n\n", 17, 0);
send (sock, buff, strlen(buff), 0);
}
}
}
//Closing SOCKET
linger l = { 1, 1 };
setsockopt(sock, SOL_SOCKET, SO_LINGER, &l, sizeof(linger));
close(sock);
}
void * http_server_loop (void *)
{
init_server();
socklen_t addrlen;
int slot=0;
// ACCEPT connections
while (1)
{
sockaddr_in clientaddr;
addrlen = sizeof(clientaddr);
int sock = accept (listenfd, (sockaddr *) &clientaddr, &addrlen);
if (sock<0)
fprintf(stderr, "accept() error num: %d\n", (void*)sock);
else
{
/* if ( fork()==0 )
{
respond(slot);
exit(0);
} */
//pthread_t thread;
//pthread_create(&thread, NULL, respond, (void*) sock);
respond((void *)sock);
}
}
return 0;
}
int start_http_server ()
{
pthread_t thread;
int err_code;
if (err_code = pthread_create(&thread, NULL, http_server_loop, NULL))
{
fprintf(stderr, "pthread_create fails with: %d\n", err_code);
return 2;
}
return(0);
}
//////////////////////////////////////////////////////////////////////////
// For testing
//////////////////////////////////////////////////////////////////////////
int main ()
{
// start_http_server();
http_server_loop(0);
usleep(0x7FFFFFFF);
}