我尝试在Linux平台上用C语言制作一个客户端/服务器系统。我想监听四个不同的端口。因此,我创建了四个文件描述符,每个端口一个。此外,该进程将 fd 绑定到端口并开始侦听它。这很好用。 此外,我使用
select()
来监听连接,但遇到了问题。在第一次运行时,程序在 select 处等待,直到客户端连接。当我用 telnet 发送一个字符串到服务器后,它会继续。但在循环的第二次运行中,程序再次在 select 处停止,并等待新客户端连接。即使我通过 telnet 发送新字符串,它也会在建立新连接后等待并处理该字符串。我使用的示例类似于此链接。
因此我不使用超时。
为什么它在选择时等待新连接?我该如何处理这个问题?
我的代码:
FD_ZERO(&read_sock);
FD_SET(fd[0], &read_sock);
FD_SET(fd[1], &read_sock);
FD_SET(fd[2], &read_sock);
FD_SET(fd[3], &read_sock);
while(TRUE){
fprintf(stderr,"Waiting for incoming connections...\n");
status = select(maxfd+1,&read_sock,NULL,NULL,NULL);
fprintf(stderr,"Number of fd: %d\n",status);
if(status>0){
for(int i=0; i< FD_SET_SIZE; i++){
if(FD_ISSET(fd[i], &read_sock)){
fd_accept=accept(fd[i],(struct sockaddr*)&client_address[i], &len);
if(client_sock[i] < 0) {
client_sock[i] = fd_accept;
}
int lenght = recv(client_sock[i],data,BUFFER-1,0);
if(lenght>0){
data[lenght] = '\0';
fprintf (stderr,"Received: %s\n", data);
}else if(lenght==0){
getpeername(fd[i],(struct sockaddr*)&client_address[i], &len);
close(fd[i]);
client_sock[i] = -1;
}else{
fprintf(stderr,"Error: %d\n",errno);
}
char string[] = "Test"; //sends a char Test to the client
write(client_sock[i],&string,sizeof(string));
}
}
}
}
select
是阻塞操作。来自手册页:
select() and pselect() allow a program to monitor multiple file descriptors,
waiting until one or more of the file descriptors become "ready" for some class
of I/O operation (e.g., input possible). A file descriptor is considered ready
if it is possible to perform the corresponding I/O operation (e.g., read(2))
without blocking.
由于您给它的描述符是侦听器套接字,因此它将阻塞,直到任一套接字上有新的套接字为止。
如果您想监听已接受套接字之一上的数据,您还需要
select
监听套接字描述符,并将其存储在 client_address
向量中。
您的代码有效地侦听新连接,接受它,读取数据,写入一些内容作为返回,然后丢弃套接字而不关闭它。