Skip to content

Commit 7ffd15b

Browse files
committed
select cli
1 parent ed3dbc5 commit 7ffd15b

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

muduo/unp/select/strcliselect01.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// 使用select重写str_cli函数,这样服务器进程一终止,客户就能马上得到通知。
2+
// 之前的版本当套接字发生某些时间时,客户可能阻塞于fgets调用。新版本改为阻塞在select调用上
3+
#include "unp.h"
4+
5+
6+
void select_str_cli(FILE *fp, int sockfd) {
7+
int maxfdp1;
8+
fd_set rset;
9+
int n;
10+
char sendline[MAXLINE], recvline[MAXLINE];
11+
12+
// 用于初始化
13+
FD_ZERO(&rset);
14+
// 使用select来驱动,区分描述符
15+
for(;;) {
16+
//设置监控的文件描述符
17+
//每次调用select之后 rset都会被清空 所以需要重新设置
18+
FD_SET(fileno(fp), &rset);
19+
FD_SET(sockfd, &rset);
20+
// 注意这里的maxfd1一定设为最大值加1 因为这个传给select可以认为是描述符的个数
21+
maxfdp1 = max(fileno(fp), sockfd) + 1;
22+
23+
// select 调用
24+
// int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout);
25+
// 第一个参数表示监听描述符的最大值,后面的参数依次表示 可读 可写 异常集合 以及超时时间
26+
// 可读集合:sock有数据可读 对端关闭写 有新的连接
27+
// 可写集合:sock有缓存空间可以写 主动关闭写端
28+
// !!当套接字上发生错误时候 可写也可读
29+
// 异常 只有出现带外数据的时候才出现异常
30+
if((n = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
31+
err_sys("select error");
32+
}
33+
if(FD_ISSET(sockfd, &rset)) {
34+
if(Readline(sockfd, recvline, MAXLINE) == 0) {
35+
err_quit("str_cli: server terminated prematurely");
36+
}
37+
Fputs(recvline, stdout);
38+
}
39+
40+
if(FD_ISSET(fileno(fp), &rset)) {
41+
if(Fgets(sendline, MAXLINE, fp) == NULL) {
42+
return;
43+
}
44+
Write(sockfd, sendline, strlen(sendline));
45+
}
46+
}
47+
}
48+
49+
int main(int argc, char **argv) {
50+
int sockfd;
51+
struct sockaddr_in servaddr;
52+
53+
if(argc!=2) {
54+
err_quit("usage: tcpcli <IPaddress>");
55+
}
56+
57+
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
58+
err_sys("sockfd error");
59+
}
60+
61+
// 基本流程
62+
bzero(&servaddr, sizeof(servaddr));
63+
servaddr.sin_family = AF_INET;
64+
servaddr.sin_port = htons(SERV_PORT);
65+
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
66+
67+
if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
68+
err_sys("connect error");
69+
}
70+
// Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
71+
select_str_cli(stdin, sockfd);
72+
exit(0);
73+
}

muduo/unp/select/strcliselect02.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "unp.h"
2+
3+
void select_str_cli(FILE *fp, int sockfd) {
4+
int maxfdp1, stdineof;
5+
fd_set rset;
6+
char buf[MAXLINE];
7+
int n;
8+
9+
stdineof = 0;
10+
FD_ZERO(&rset);
11+
for(;;) {
12+
if(stdineof==0) {
13+
FD_SET(sockfd, &rset);
14+
}
15+
FD_SET(fileno(fp), &rset);
16+
maxfdp1 = max(fileno(fp), sockfd) + 1;
17+
18+
if((select(maxfdp1, &rset, NULL, NULL, NULL))<0) {
19+
err_sys("select error");
20+
}
21+
22+
if(FD_ISSET(sockfd, &rset)) {
23+
if((n=Readline(sockfd, buf, MAXLINE)) == 0) {
24+
if(stdineof==1) {
25+
return;
26+
} else {
27+
err_quit("str_cli: server terminated");
28+
}
29+
}
30+
Write(fileno(fp), buf, n);
31+
}
32+
33+
if(FD_ISSET(fileno(fp), &rset)) {
34+
if((n=Readline(fileno(fp), buf, MAXLINE)) == 0) {
35+
stdineof = 1;
36+
// 一般使用close来关闭一个套接字
37+
// 但是使用close有2个局限性, 首先close先把描述符的引用计数减去1 只有在引用计数为0的时候才会关闭套接字
38+
// 其次是close终止的时候是读写全都关闭 但是套接字是全双工的 有时候我们需要告诉对端我们完成了数据发送,还可以接受对端的数据
39+
// 即关闭写的这一半 也叫半关闭
40+
41+
// 使用shutdown就可以解决上面的问题 使用shutdown的时候不管引用计数是否为0都照样关闭
42+
// 还可以通过设置第二个参数 来选择如何关闭
43+
if(shutdown(sockfd, SHUT_WR) < 0) {
44+
err_sys("shutdown error");
45+
}
46+
FD_CLR(fileno(fp), &rset);
47+
continue;
48+
}
49+
Write(sockfd, buf, n);
50+
}
51+
}
52+
}
53+
54+
int main(int argc, char **argv) {
55+
int sockfd;
56+
struct sockaddr_in servaddr;
57+
int n;
58+
59+
if(argc != 2) {
60+
err_quit("usage: <IPAddress>");
61+
}
62+
63+
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0){
64+
err_sys("socket error");
65+
}
66+
67+
bzero(&servaddr, sizeof(servaddr));
68+
servaddr.sin_family = AF_INET;
69+
servaddr.sin_port = htons(SERV_PORT);
70+
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
71+
72+
if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
73+
err_sys("connect error");
74+
}
75+
76+
select_str_cli(stdin, sockfd);
77+
exit(0);
78+
}

0 commit comments

Comments
 (0)