我正在尝试使用套接字为聊天服务器构建服务器和客户端。我知道我应该使用select()从多个套接字获取输入,但我不知道如何做,仍然正确地读取它们。正如我的代码所在,它从一个客户端读取完全正常,但当两个客户端打开时,它会忽略第二个客户端执行的所有操作,直到第一个客户端关闭。
我想知道如何正确实现select以确保我可以从多个套接字中获取输入。提前谢谢。
#include "../../include/my.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void interrupt();
void interrupt()
{
my_str("Server exiting.\n");
exit(0);
}
int str_to_num(char* str)
{
int i = 0;
int numDigits = 0;
int ret = 0;
while (str[numDigits] != '\0')
{
numDigits++;
}
while (i < numDigits)
{
int digit = str[i];
if (digit < 48 && digit > 57)
return -1;
digit -= 48;
ret += digit * my_pow(10, numDigits - i - 1);
i++;
}
return ret;
}
char* add_null_term(char* str)
{
int i = 0;
while (str[i] != '\0')
i++;
str[i] = '\0';
return str;
}
int main(int argc, char **argv)
{
int sockfd, newsockfd, portnum;
int len;
char buffer[256];
/*char *username = (char*)malloc(256*sizeof(char));*/
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
/*check args*/
if (argc < 2)
{
my_str("Usage: ./server <port_number>\n");
exit(0);
}
portnum = str_to_num(argv[1]);
if (portnum < 1024)
{
perror("Ports below 1024 are reserved for root access.\n");
exit(0);
}
if (portnum < 1 || portnum > 65535)
{
my_str("Port must be between 1 and 65535\n");
exit(0);
}
signal(SIGINT, interrupt);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portnum);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
{
perror("bind");
exit(0);
}
listen(sockfd, 5);
clilen = sizeof(cli_addr);
while(1)
{
if ((newsockfd=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen)) < 0)
{
perror("accept");
exit(0);
}
usleep(2000);
my_str("Server received: ");
while ((len = read(newsockfd, &buffer, 256)) > 0)
{
buffer[my_strlen(buffer)] = '\0';
if (my_strcmp(buffer, "/") == 0)
{
my_str("Error: command ");
my_str(buffer);
my_str("not found.\n");
bzero((char*)&buffer, sizeof(buffer));
}
/*if (count == 0)
{
my_strcpy(username, buffer);
my_str("setting nickname to: ");
my_str(username);
bzero((char*)&buffer, sizeof(buffer));
my_str(buffer);
count++;
my_str("\n");
}*/
/*else if (my_strncmp(buffer, "/me", 3) == 0)
{
my_str(username);
my_str(" ");
my_str(&buffer[4]);
bzero((char*)&buffer, sizeof(buffer));
my_str("\n");
}
else if (my_strncmp(buffer, "/nick", 5) == 0)
{
my_str("Changing nickname of ");
my_str(username);
my_strcpy(username, &buffer[6]);
my_str(" to ");
my_str(username);
bzero((char*)&buffer, sizeof(buffer));
my_str("\n");
}*/
/*else
{*/
/*my_str(username);
my_str(": ");*/
my_str(buffer);
bzero((char*)&buffer, sizeof(buffer));
my_str(buffer);
my_str("\n");
/*}*/
}
my_str("\nServer: Message end. Waiting for next connection.\n");
}
return 0;
}
答案 0 :(得分:0)
如果您的问题是如何在服务器中使用select()... 这是一个技巧的顶部片段 让你开始...记住所有错误检查不是 目前,并没有优化以循环功能 基础...
listen(sockfd, SOMAXCONN)
fd_set my_set;
fd_set wk_set;
FD_ZERO(&my_set); /* initialize fd_set */
FD_SET(sock_fd, &my_set) /* put listener into fd_set */
max_fd = sockfd;
while( TRUE )
{
memcpy(&wk_set, &my_set, sizeof(my_set));
rc = select(max_fd + 1, &wk_set, NULL, NULL, NULL )
if ( rc == -1 )
{
if ( errno == EINTR )
continue;
printf("select failed: errno = %d\n", errno);
exit(1);
}
for(i = 0; i < max_fd; i++) /* check everything in wk_set */
{
if ( FD_ISSET(i, &wk_set)
{
if ( i == sockfd ) /* is it the listener socket?? */
{
wk_sock=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if ( wk_sock == -1 )
{
printf("accept failed: errno=%d\n", errno);
exit(1);
}
FD_SET(wk_sock, &my_set); /* put into fd_set */
if ( wk_sock > max_sock )
max_sock = wk_sock;
}else{
/* ready to read from this socket */
recv_len = recv(i, .... )
if ( recv_len == 0 ) /* client disconnected */
{
close(i);
FD_CLR(i, &my_set);
if (i == max_fd )
{
for(x=0;x<max_fd;x++) /* find new max_fd */
{
if ( FD_ISSET(x, &my_set )
max_fd = x;
}
}
} else {
handle message from client
}
}
}
}
}