我在Linux下使用select()在C中创建了一个TCP客户端服务器程序。我想知道如何限制连接到服务器的客户端数量。那就是我可以在他们接受之前接受() - 编辑。
这是代码,对不起评论的语言。我仍然没有把它放到哪里。
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
/* portul folosit */
#define PORT 2728
extern int errno; /* eroarea returnata de unele apeluri */
/* functie de convertire a adresei IP a clientului in sir de caractere */
char * conv_addr (struct sockaddr_in address)
{
static char str[25];
char port[7];
/* adresa IP a clientului */
strcpy (str, inet_ntoa (address.sin_addr));
/* portul utilizat de client */
bzero (port, 7);
sprintf (port, ":%d", ntohs (address.sin_port));
strcat (str, port);
return (str);
}
int v[4]; //vector cu 5 tipuri de mancare
/* programul */
int main ()
{ int nrclienti=0; v[0]=0; v[1]=0; v[2]=0; v[3]=0; v[4]=0;
int inchid=1;
int x,max,pmax;max=v[0];pmax=0;int pref;
struct sockaddr_in server; /* structurile pentru server si clienti */
struct sockaddr_in from;
fd_set readfds; /* multimea descriptorilor de citire */
fd_set actfds; /* multimea descriptorilor activi */
struct timeval tv; /* structura de timp pentru select() */
int sd, client; /* descriptori de socket */
int optval=1; /* optiune folosita pentru setsockopt()*/
int fd; /* descriptor folosit pentru
parcurgerea listelor de descriptori */
int nfds; /* numarul maxim de descriptori */
int len; /* lungimea structurii sockaddr_in */
/* creare socket */
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server] Eroare la socket().\n");
return errno;
}
/*setam pentru socket optiunea SO_REUSEADDR */
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&optval,sizeof(optval));
/* pregatim structurile de date */
bzero (&server, sizeof (server));
/* umplem structura folosita de server */
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
/* atasam socketul */
if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server] Eroare la bind().\n");
return errno;
}
/* punem serverul sa asculte daca vin clienti sa se conecteze */
if (listen (sd, 5) == -1)
{
perror ("[server] Eroare la listen().\n");
return errno;
}
/* completam multimea de descriptori de citire */
FD_ZERO (&actfds); /* initial, multimea este vida */
FD_SET (sd, &actfds); /* includem in multime socketul creat */
tv.tv_sec = 1; /* se va astepta un timp de 1 sec. */
tv.tv_usec = 0;
/* valoarea maxima a descriptorilor folositi */
nfds = sd;
printf ("[server] Asteptam la portul %d...\n", PORT);
fflush (stdout);
/* servim in mod concurent clientii... */
while (inchid)
{ /* ajustam multimea descriptorilor activi (efectiv utilizati) */
bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds));
/* apelul select() */
if (select (nfds+1, &readfds, NULL, NULL, &tv) < 0)
{
perror ("[server] Eroare la select().\n");
return errno;
}
/* vedem daca e pregatit socketul pentru a-i accepta pe clienti */
if (FD_ISSET (sd, &readfds))
{
/* pregatirea structurii client */
len = sizeof (from);
bzero (&from, sizeof (from));
/* a venit un client, acceptam conexiunea */
client = accept (sd, (struct sockaddr *) &from, &len);
/* eroare la acceptarea conexiunii de la un client */
if (client < 0)
{
perror ("[server] Eroare la accept().\n");
continue;
}
if (nfds < client) /* ajusteaza valoarea maximului */
nfds = client;
printf("[server] S-a conectat clientul cu descriptorul %d, de la adresa %s.\n",client, conv_addr (from));
/* includem in lista de descriptori activi si acest socket */
FD_SET (client, &actfds);
fflush (stdout);
}
/* vedem daca e pregatit vreun socket client pentru a trimite raspunsul */
for (fd = 0; fd <= nfds; fd++) /* parcurgem multimea de descriptori */
{
/* este un socket de citire pregatit? */
if (fd != sd && FD_ISSET (fd, &readfds))
{ //func
char buffer[100]; /* mesajul */
int bytes; /* numarul de octeti cititi/scrisi */
char msg[100]; //mesajul primit de la client
char msgrasp[100]; //mesaj de raspuns pentru client
int replies=0;
do
{
//citim mesajul de la client
bytes = read (fd, msg, sizeof (buffer));
if (bytes < 0)
{
perror ("Eroare la read() de la client.\n");
return 0;
}
printf ("[server]Clientul cu descriptorul %d a ales mancarea %s\n",fd, msg);
int poz; //comanda alease introdusa in vectorul de comenzi
poz = msg[0] - '0';
v[poz-1]++;
//decidem felul preferat din meniu
printf("[server]");
for(x=0;x<=4;x++)
if (max<v[x]) {max=v[x];pmax=x;}
pref=pmax+1;
for(x=0;x<=4;x++) printf("%d|",v[x]);
printf(" Val max e %d\n",pref);
/*pregatim mesajul de raspuns */
bzero(msgrasp,100);
sprintf(msgrasp, "%d", pref);
//daca clientului corespunde cu mancarea favorita, trimitem raspunsul
if (msg[0]==msgrasp[0]) sprintf(msgrasp, "%d", 1);
else sprintf(msgrasp, "%d", 0);
printf("[server]Trimitem %s clientului %d\n",msgrasp,fd);
if (bytes && write (fd, msgrasp, bytes) < 0)
{
perror ("[server] Eroare la write() catre client.\n");
return 0;
}
//func
replies++;
}while((msgrasp[0]!=49)&&(replies<3));
printf ("[server] S-a deconectat clientul cu descriptorul %d.\n\n",fd);
fflush (stdout);
close (fd); /* inchidem conexiunea cu clientul */
FD_CLR (fd, &actfds);/* scoatem si din multime */
}
} /* for */
} /* while */
close(sd);} /* main */
答案 0 :(得分:0)
好吧,如果您不需要客户端,您可能不会接受()他:)因此您可以限制当前正在处理的客户端数量。只需忽略主套接字上的事件即可。
您也可以使用TCP积压限制尚未接受的客户端队列的大小,请注意listen()
的第二个参数
但通常它并不完全,呃,礼貌。也许你应该重新思考你的整个任务,并决定如何同时处理更多的客户。
答案 1 :(得分:0)
我将假设您使用select()
运行非线程非分叉应用程序。如果没有,那么您将需要稍微修改一下但不多。
在select()
之前,您将使用fd_set
将与开放会话相对应的每个fd添加到FD_SET
;当你循环时,你可以数这些。您还将添加您的侦听器fd。如果打开的连接数达到最大值,则省略第二步。
请注意,稍后仍可接受开放式连接 - 请参阅backlog
listen()
的工作原理。