一、实验要求
在前期ECHO代码的基础上,利用I/O复用完成单线程并发服务器的实现。
二、实验分析
使用select实现单线程ECHO服务器:
- 在熟知端口上打开一个被动套接字
- 使用系统函数getdtablesize来决定描述符最大个数
- 使用FD_ZERO和FD_SET创建一个比特向量,对应于希望测试的套接字描述符
- select等待一个或者多个描述符就绪 FD_ISSET测试哪个描述符就绪
- FD_CLR关闭连接后,从描述符组中删除
三、实验内容
1.tcp_server.c
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h> /*for errno*/
#define BUFFER_SIZE 1024
#define QLEN 32
int process_conn_server(int fd);
int main(int argc, char *argv[])
{
char *service = "echo";
struct sockaddr_in fsin;
int msock;
fd_set rfds; //лв╫свжап╠М
fd_set afds;
int alen;
int fd, nfds;
switch(argc)
{
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: TCPmechod [PORT]\n");
}
msock = passiveTCP(service, QLEN);
nfds = getdtablesize();
FD_ZERO(&afds);
FD_SET(msock, &afds);
int count = 0;
while(1)
{
memcpy(&rfds, &afds, sizeof(rfds));
if(select(nfds, &rfds, (fd_set*)0, (fd_set*)0, (struct timeval *)0) < 0)
errexit("select: %s\n", strerror(errno));
if(FD_ISSET(msock, &rfds)){
int ssock;
alen = sizeof(fsin);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0)
errexit("accept: %s\n", strerror(errno));
FD_SET(ssock, &afds);
}
for(fd = 0; fd < nfds; fd++)
{
if(fd != msock && FD_ISSET(fd, &rfds)){
if(process_conn_server(fd) == 0){
(void) close(fd);
FD_CLR(fd, &afds);
}
}
}
}
}
int process_conn_server(int fd)
{
char buf[BUFFER_SIZE];
int cc;
cc = read(fd, buf, sizeof(buf));
if(cc < 0)
errexit("echo read: %s\n", strerror(errno));
if(cc == 0)
return cc;
printf("server read: %s size:%d\n", buf, strlen(buf));
if(cc && write(fd, buf , cc) < 0)
errexit("echo write: %s\n", strerror(errno));
return cc;
}
2.tcp_client.c
//tcp_client.c
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h> /*for errno*/
#define BUFFER_SIZE 1024
int process_conn_client(int socket);
int main(int argc, char * argv[])
{
char *host = "localhost";
char *service = "echo";
switch(argc)
{
case 1:
break;
case 3:
service = argv[2];
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: TCPfiletransfer [ host [port]]\n");
exit(1);
}
int socket = connectTCP(host, service);
process_conn_client(socket);
close(socket);
}
int process_conn_client(int socket)
{
char buf[BUFFER_SIZE];
int cc;
scanf("%s", buf); /*不能读空格*/
// cc = read(0, buf, BUFFER_SIZE); /*能读出空格,但会读取回车*/
cc = write(socket, buf, sizeof(buf));
if(cc < 0)
errexit("client write: %s\n", strerror(errno));
if(cc && read(socket, buf, cc) < 0)
errexit("client read: %s\n", strerror(errno));
printf("client read: %s\n",buf);
return cc;
}
运行结果如下:
服务器:
客户端: