并发服务器的第二种实现方法:I/O复用
服务器端:
#include
#include
#include
#include
#include
using namespace std;
char buf[1024];
int main(int argc, char **argv)
{
int ser_sock, cli_sock;
sockaddr_in ser_addr, cli_addr;
ser_sock = socket(PF_INET, SOCK_STREAM, 0);
if(ser_sock == -1) puts("socket error");
int opt = 1;
setsockopt(ser_sock, SOL_SOCKET, SO_REUSEADDR, &opt, 4);
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(atoi(argv[1]));
if(bind(ser_sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) == -1)
puts("bind error");
if(listen(ser_sock, 5) == -1) puts("listen error");
fd_set fd, copy_fd;
FD_ZERO(&fd);
FD_SET(ser_sock, &fd);
int fd_max = ser_sock;
timeval timeout;
socklen_t s_len = sizeof(cli_addr);
while(1)
{
timeout.tv_sec = 5;
timeout.tv_usec = 0;
copy_fd = fd;
int fd_num = select(fd_max+1, ©_fd, 0, 0, &timeout);
if(fd_num == 0) continue;
for(int i = 0; i <= fd_max; i++)
{
if(FD_ISSET(i, ©_fd))
{
if(i == ser_sock)//accept时服务器套接字发生变化
{
cli_sock = accept(ser_sock, (sockaddr *)&cli_addr, &s_len);
FD_SET(cli_sock, &fd);
fd_max = max(fd_max, cli_sock);
}
else //传输数据时客户端套接字发生变化
{
int len = read(i, buf, 100);
if(!len) //eof时删除fd数组信息并关闭套接字
{
close(i);
FD_CLR(i, &fd);
printf("close client %d\n", i);
}
else
{
buf[len] = 0;
printf("message form client %d : %s\n", i, buf);
write(i, buf, 100);
}
}
}
}
}
close(ser_sock);
return 0;
}
客户端:
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char **argv)
{
int sock;
sock = socket(PF_INET, SOCK_STREAM, 0);
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
connect(sock, (sockaddr *)&addr, sizeof(addr));
char buf[1024];
while(1)
{
scanf("%s", buf);
int l = strlen(buf);
if(strcmp(buf, "q") == 0) break;
write(sock, buf, l);
sleep(0.5);
int len = read(sock, buf, 100);
buf[len] = 0;
printf("message from server : %s\n", buf);
}
close(sock);
return 0;
}