文件I/O方式比较
1. 阻塞式文件IO
2. 非阻塞式文件IO
3. 多路复用IO
4. 信号驱动IO(也叫驱动异步IO)
IO阻塞与非阻塞操作
阻塞:如果没有数据可操作,该函数调用将阻塞,导致对应进程暂停执行,当有数据继续执行并返回。
默认read/write函数,以及recv/send函数采用阻塞方式
非阻塞:需要进程立即返回,则需要设置为非阻塞方式,即如果没有数据可接收就立即返回-1表示接收失败,并修改系统全局变量errno。
socket读写,以非阻塞方式调用recv()函数返回时,没有数据可读,将修改errno变量的值为“EAGAIN”,表示recv读数据时,对方没有发送数据过来。
非阻塞应用示例
发送端代码
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <resolv.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define MAXBUF 128
- int main(int argc, char **argv)
- {
- int sockfd, ret, i;
- struct sockaddr_in dest, mine;
- char buffer[MAXBUF + 1];
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("Socket");
- exit(EXIT_FAILURE);
- }
- bzero(&dest, sizeof(dest));
- dest.sin_family = AF_INET;
- dest.sin_port = htons(7838);
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- bzero(&mine, sizeof(mine));
- mine.sin_family = AF_INET;
- mine.sin_port = htons(7839);
- if (inet_aton(argv[2], (struct in_addr *) &mine.sin_addr.s_addr) == 0)
- {
- perror(argv[2]);
- exit(EXIT_FAILURE);
- }
- if (bind(sockfd, (struct sockaddr *) &mine, sizeof(struct sockaddr)) == -1)
- {
- perror(argv[3]);
- exit(EXIT_FAILURE);
- }
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
- {
- perror("Connect ");
- exit(EXIT_FAILURE);
- }
- if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1)
- {
- perror("fcntl");
- exit(EXIT_FAILURE);
- }
- while(1)
- {
- bzero(buffer, MAXBUF + 1);
- ret = recv(sockfd, buffer, MAXBUF, 0);
- if(ret > 0)
- {
- printf("get %d message:%s", ret, buffer);
- ret=0;
- }
- else if(ret < 0)
- {
- if(errno == EAGAIN)
- {
- errno=0;
- continue;
- }
- else
- {
- perror("recv");
- exit(EXIT_FAILURE);
- }
- }
- memset( buffer,'\0',MAXBUF+1);
- printf("input message to send:");
- fgets( buffer,MAXBUF,stdin);
- if((ret=send(sockfd,buffer,strlen(buffer),0))==-1)
- {
- perror("send");
- exit(EXIT_FAILURE);
- }
- }
- close(sockfd);
- return 0;
- }
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <errno.h>
- #define BUFSIZE 128
- int main(int argc,char *argv[])
- {
- int server_sockfd, client_sockfd;
- int server_len, client_len;
- struct sockaddr_in server_address;
- struct sockaddr_in client_address;
- int i,byte;
- char char_send[BUFSIZE];
- server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
- server_address.sin_family = AF_INET;
- if (inet_aton(argv[1], (struct in_addr *) & server_address.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- server_address.sin_port = htons(7838);
- server_len = sizeof(server_address);
- bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
- listen(server_sockfd, 5);
- printf("server waiting for connect\n");
- client_len = sizeof(client_address);
- client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);
- for(i=0;i<5;i++)
- {
- memset(char_send,'\0',BUFSIZE);
- printf("input message to send:");
- fgets(char_send,BUFSIZE,stdin);
- if((byte=send(client_sockfd,char_send,strlen(char_send),0))==-1)
- {
- perror("send");
- exit(EXIT_FAILURE);
- }
- memset(char_send,'\0',BUFSIZE);
- byte = recv(client_sockfd, char_send, BUFSIZE,MSG_DONTWAIT);
- if(byte > 0)
- {
- printf("get %d message:%s", byte, char_send);
- byte=0;
- }
- else if(byte<0)
- {
- if(errno==EAGAIN)
- {
- errno=0;
- continue;
- }
- else
- {
- perror("recv");
- exit(EXIT_FAILURE);
- }
- }
- }
- shutdown(client_sockfd,2);
- shutdown(server_sockfd,2);
- }
- $ ./tcp_unblock_server 172.18.229.62
- server waiting for connect
- input message to send:hello
- input message to send:test
- get 3 message:hi
- input message to send:go
- input message to send:read
- input message to send:why
- $ ./tcp_unblock_client 172.18.229.62 172.18.229.62
- get 6 message:hello
- input message to send:hi
- get 5 message:test
- input message to send:go
- get 12 message:go
- read
- why
- input message to send:hi
select函数
select提供轮循等待的方式从多个文件描述符中获取状态发变后的消息 。
第1个参数指定要检测的文件描述符的范围。测试范围在0到nfds−1之间的文件描述符(nfds=这些文件描述符中的最大值+1)。
第2、3、4三个参数类型都是fd_set *。这三个参数都是文件描述符的集合。
dfds包含所有因状态变成可读而触发select()函数返回的文件描述符;
wtfds包含所有因状态变成可写而触发select()函数返回的文件描述符;
exfds包含所有因状态发生特殊异常(例如带外数据到来)而触发select()函数返回的文件描述符
文件描述符集合操作
最后一个参数timeout显然是一个超时时限,其类型是struct timeval * 。
如果函数执行错误,将返回-1;
如果因超时而返回,即在timeout所描述的时间范围内没有任何描述符出现异常,则返回0;
如果因一个或多个文件描述符异常而返回,其返回值为产生异常的文件描述符数,并在相应文件描述符集合中清除未产生异常的文件描述符记录,因此,返回后可以根据文件描述符集合的记录查找出是哪一个文件描述符返回。
基本示例
检测某个socket是否有数据可读
pselect函数
poll与ppoll函数
poll函数
poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。
- #include <poll.h>
- int poll(struct pollfd *fd, nfds_t nfds, int timeout);
1)第一个参数:一个结构数组,struct pollfd结构如下:
- struct pollfd{
- int fd; //文件描述符
- short events; //请求的事件
- short revents; //返回的事件
- };
poll函数的事件标志符值
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
2)第二个参数nfds:要监视的描述符的数目。
3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果 它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。
timeout值 说明
INFTIM 永远等待
0 立即返回,不阻塞进程
>0 等待指定数目的毫秒数
ppoll函数
- #include <poll.h>
- int ppoll(struct pollfd *fd, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);
与pselect一样,ppoll函数可以在阻塞过程中屏蔽某些信号,而在timeout时间上,ppoll的时间精度更高。
多路复用应用示例
服务器代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #define MAXBUF 1024
- int main(int argc, char **argv)
- {
- int sockfd, new_fd;
- socklen_t len;
- struct sockaddr_in my_addr, their_addr;
- unsigned int myport, lisnum;
- char buf[MAXBUF + 1];
- fd_set rfds;
- struct timeval tv;
- int retval, maxfd = -1;
- if (argv[2])
- myport = atoi(argv[2]);
- else
- myport = 7838;
- if (argv[3])
- lisnum = atoi(argv[3]);
- else
- lisnum = 2;
- if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
- bzero(&my_addr, sizeof(my_addr));
- my_addr.sin_family = PF_INET;
- my_addr.sin_port = htons(myport);
- if (argv[1])
- my_addr.sin_addr.s_addr = inet_addr(argv[1]);
- else
- my_addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
- perror("bind");
- exit(EXIT_FAILURE);
- }
- if (listen(sockfd, lisnum) == -1) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
- while (1)
- {
- printf ("\n----wait for new connect\n");
- len = sizeof(struct sockaddr);
- if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) {
- perror("accept");
- exit(errno);
- } else
- printf("server: got connection from %s, port %d, socket %d\n",
- inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);
- while (1)
- {
- FD_ZERO(&rfds);
- FD_SET(0, &rfds);
- FD_SET(new_fd, &rfds);
- maxfd = new_fd;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
- perror("select");
- exit(EXIT_FAILURE);
- } else if (retval == 0) {
- continue;
- }
- else
- {
- if (FD_ISSET(0, &rfds))
- {
- bzero(buf, MAXBUF + 1);
- fgets(buf, MAXBUF, stdin);
- if (!strncasecmp(buf, "quit", 4)) {
- printf("i will quit!\n");
- break;
- }
- len = send(new_fd, buf, strlen(buf) - 1, 0);
- if (len > 0)
- printf ("send successful,%d byte send!\n",len);
- else {
- printf("send failure!");
- break;
- }
- }
- if (FD_ISSET(new_fd, &rfds))
- {
- bzero(buf, MAXBUF + 1);
- len = recv(new_fd, buf, MAXBUF, 0);
- if (len > 0)
- printf ("recv success :'%s',%dbyte recv\n", buf, len);
- else
- {
- if (len < 0)
- printf("recv failure\n");
- else
- {
- printf("the ohter one end ,quit\n");
- break;
- }
- }
- }
- }
- }
- close(new_fd);
- printf("need othe connecdt (no->quit)");
- fflush(stdout);
- bzero(buf, MAXBUF + 1);
- fgets(buf, MAXBUF, stdin);
- if (!strncasecmp(buf, "no", 2))
- {
- printf("quit!\n");
- break;
- }
- }
- close(sockfd);
- return 0;
- }
客户端代码
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <resolv.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #define MAXBUF 1024
- int main(int argc, char **argv)
- {
- int sockfd, len;
- struct sockaddr_in dest;
- char buffer[MAXBUF + 1];
- fd_set rfds;
- struct timeval tv;
- int retval, maxfd = -1;
- if (argc != 3)
- {
- printf("argv format errno,pls:\n\t\t%s IP port\n",argv[0], argv[0]);
- exit(EXIT_FAILURE);
- }
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("Socket");
- exit(EXIT_FAILURE);
- }
- bzero(&dest, sizeof(dest));
- dest.sin_family = AF_INET;
- dest.sin_port = htons(atoi(argv[2]));
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
- {
- perror("Connect ");
- exit(EXIT_FAILURE);
- }
- printf("\nget ready pls chat\n");
- while (1)
- {
- FD_ZERO(&rfds);
- FD_SET(0, &rfds);
- FD_SET(sockfd, &rfds);
- maxfd = sockfd;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
- printf("select %s", strerror(errno));
- break;
- }
- else if (retval == 0)
- continue;
- else
- {
- if (FD_ISSET(sockfd, &rfds))
- {
- bzero(buffer, MAXBUF + 1);
- len = recv(sockfd, buffer, MAXBUF, 0);
- if (len > 0)
- printf ("recv message:'%s',%d byte recv\n",buffer, len);
- else
- {
- if (len < 0)
- printf ("message recv failure\n");
- else
- {
- printf("the othe quit ,quit\n");
- break;
- }
- }
- }
- if (FD_ISSET(0, &rfds))
- {
- bzero(buffer, MAXBUF + 1);
- fgets(buffer, MAXBUF, stdin);
- if (!strncasecmp(buffer, "quit", 4)) {
- printf("i will quit\n");
- break;
- }
- len = send(sockfd, buffer, strlen(buffer) - 1, 0);
- if (len < 0) {
- printf ("message send failure");
- break;
- } else
- printf
- ("send success,%d byte send\n",len);
- }
- }
- }
- close(sockfd);
- return 0;
- }
- $ ./tcp_sy_chat_server 172.18.229.62 8000
- ----wait for new connect
- server: got connection from 172.18.229.62, port 55410, socket 4
- recv success :'hello',5byte recv
- recv success :'test',4byte recv
- recv success :'why',3byte recv
- ready
- send successful,5 byte send!
- end
- send successful,3 byte send!
- quit
- i will quit!
- need othe connecdt (no->quit)no
- quit!
- $ ./tcp_sy_chat_client 172.18.229.62 8000
- get ready pls chat
- hello
- send success,5 byte send
- test
- send success,4 byte send
- why
- send success,3 byte send
- recv message:'ready',5 byte recv
- recv message:'end',3 byte recv
- the othe quit ,quit
原文链接
http://blog.csdn.net/geng823/article/details/41750405
文件I/O方式比较
1. 阻塞式文件IO
2. 非阻塞式文件IO
3. 多路复用IO
4. 信号驱动IO(也叫驱动异步IO)
IO阻塞与非阻塞操作
阻塞:如果没有数据可操作,该函数调用将阻塞,导致对应进程暂停执行,当有数据继续执行并返回。
默认read/write函数,以及recv/send函数采用阻塞方式
非阻塞:需要进程立即返回,则需要设置为非阻塞方式,即如果没有数据可接收就立即返回-1表示接收失败,并修改系统全局变量errno。
socket读写,以非阻塞方式调用recv()函数返回时,没有数据可读,将修改errno变量的值为“EAGAIN”,表示recv读数据时,对方没有发送数据过来。
非阻塞应用示例
发送端代码
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <resolv.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define MAXBUF 128
- int main(int argc, char **argv)
- {
- int sockfd, ret, i;
- struct sockaddr_in dest, mine;
- char buffer[MAXBUF + 1];
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("Socket");
- exit(EXIT_FAILURE);
- }
- bzero(&dest, sizeof(dest));
- dest.sin_family = AF_INET;
- dest.sin_port = htons(7838);
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- bzero(&mine, sizeof(mine));
- mine.sin_family = AF_INET;
- mine.sin_port = htons(7839);
- if (inet_aton(argv[2], (struct in_addr *) &mine.sin_addr.s_addr) == 0)
- {
- perror(argv[2]);
- exit(EXIT_FAILURE);
- }
- if (bind(sockfd, (struct sockaddr *) &mine, sizeof(struct sockaddr)) == -1)
- {
- perror(argv[3]);
- exit(EXIT_FAILURE);
- }
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
- {
- perror("Connect ");
- exit(EXIT_FAILURE);
- }
- if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1)
- {
- perror("fcntl");
- exit(EXIT_FAILURE);
- }
- while(1)
- {
- bzero(buffer, MAXBUF + 1);
- ret = recv(sockfd, buffer, MAXBUF, 0);
- if(ret > 0)
- {
- printf("get %d message:%s", ret, buffer);
- ret=0;
- }
- else if(ret < 0)
- {
- if(errno == EAGAIN)
- {
- errno=0;
- continue;
- }
- else
- {
- perror("recv");
- exit(EXIT_FAILURE);
- }
- }
- memset( buffer,'\0',MAXBUF+1);
- printf("input message to send:");
- fgets( buffer,MAXBUF,stdin);
- if((ret=send(sockfd,buffer,strlen(buffer),0))==-1)
- {
- perror("send");
- exit(EXIT_FAILURE);
- }
- }
- close(sockfd);
- return 0;
- }
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <errno.h>
- #define BUFSIZE 128
- int main(int argc,char *argv[])
- {
- int server_sockfd, client_sockfd;
- int server_len, client_len;
- struct sockaddr_in server_address;
- struct sockaddr_in client_address;
- int i,byte;
- char char_send[BUFSIZE];
- server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
- server_address.sin_family = AF_INET;
- if (inet_aton(argv[1], (struct in_addr *) & server_address.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- server_address.sin_port = htons(7838);
- server_len = sizeof(server_address);
- bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
- listen(server_sockfd, 5);
- printf("server waiting for connect\n");
- client_len = sizeof(client_address);
- client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);
- for(i=0;i<5;i++)
- {
- memset(char_send,'\0',BUFSIZE);
- printf("input message to send:");
- fgets(char_send,BUFSIZE,stdin);
- if((byte=send(client_sockfd,char_send,strlen(char_send),0))==-1)
- {
- perror("send");
- exit(EXIT_FAILURE);
- }
- memset(char_send,'\0',BUFSIZE);
- byte = recv(client_sockfd, char_send, BUFSIZE,MSG_DONTWAIT);
- if(byte > 0)
- {
- printf("get %d message:%s", byte, char_send);
- byte=0;
- }
- else if(byte<0)
- {
- if(errno==EAGAIN)
- {
- errno=0;
- continue;
- }
- else
- {
- perror("recv");
- exit(EXIT_FAILURE);
- }
- }
- }
- shutdown(client_sockfd,2);
- shutdown(server_sockfd,2);
- }
- $ ./tcp_unblock_server 172.18.229.62
- server waiting for connect
- input message to send:hello
- input message to send:test
- get 3 message:hi
- input message to send:go
- input message to send:read
- input message to send:why
- $ ./tcp_unblock_client 172.18.229.62 172.18.229.62
- get 6 message:hello
- input message to send:hi
- get 5 message:test
- input message to send:go
- get 12 message:go
- read
- why
- input message to send:hi
select函数
select提供轮循等待的方式从多个文件描述符中获取状态发变后的消息 。
第1个参数指定要检测的文件描述符的范围。测试范围在0到nfds−1之间的文件描述符(nfds=这些文件描述符中的最大值+1)。
第2、3、4三个参数类型都是fd_set *。这三个参数都是文件描述符的集合。
dfds包含所有因状态变成可读而触发select()函数返回的文件描述符;
wtfds包含所有因状态变成可写而触发select()函数返回的文件描述符;
exfds包含所有因状态发生特殊异常(例如带外数据到来)而触发select()函数返回的文件描述符
文件描述符集合操作
最后一个参数timeout显然是一个超时时限,其类型是struct timeval * 。
如果函数执行错误,将返回-1;
如果因超时而返回,即在timeout所描述的时间范围内没有任何描述符出现异常,则返回0;
如果因一个或多个文件描述符异常而返回,其返回值为产生异常的文件描述符数,并在相应文件描述符集合中清除未产生异常的文件描述符记录,因此,返回后可以根据文件描述符集合的记录查找出是哪一个文件描述符返回。
基本示例
检测某个socket是否有数据可读
pselect函数
poll与ppoll函数
poll函数
poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。
- #include <poll.h>
- int poll(struct pollfd *fd, nfds_t nfds, int timeout);
1)第一个参数:一个结构数组,struct pollfd结构如下:
- struct pollfd{
- int fd; //文件描述符
- short events; //请求的事件
- short revents; //返回的事件
- };
poll函数的事件标志符值
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
2)第二个参数nfds:要监视的描述符的数目。
3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果 它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。
timeout值 说明
INFTIM 永远等待
0 立即返回,不阻塞进程
>0 等待指定数目的毫秒数
ppoll函数
- #include <poll.h>
- int ppoll(struct pollfd *fd, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);
与pselect一样,ppoll函数可以在阻塞过程中屏蔽某些信号,而在timeout时间上,ppoll的时间精度更高。
多路复用应用示例
服务器代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #define MAXBUF 1024
- int main(int argc, char **argv)
- {
- int sockfd, new_fd;
- socklen_t len;
- struct sockaddr_in my_addr, their_addr;
- unsigned int myport, lisnum;
- char buf[MAXBUF + 1];
- fd_set rfds;
- struct timeval tv;
- int retval, maxfd = -1;
- if (argv[2])
- myport = atoi(argv[2]);
- else
- myport = 7838;
- if (argv[3])
- lisnum = atoi(argv[3]);
- else
- lisnum = 2;
- if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
- bzero(&my_addr, sizeof(my_addr));
- my_addr.sin_family = PF_INET;
- my_addr.sin_port = htons(myport);
- if (argv[1])
- my_addr.sin_addr.s_addr = inet_addr(argv[1]);
- else
- my_addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
- perror("bind");
- exit(EXIT_FAILURE);
- }
- if (listen(sockfd, lisnum) == -1) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
- while (1)
- {
- printf ("\n----wait for new connect\n");
- len = sizeof(struct sockaddr);
- if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) {
- perror("accept");
- exit(errno);
- } else
- printf("server: got connection from %s, port %d, socket %d\n",
- inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);
- while (1)
- {
- FD_ZERO(&rfds);
- FD_SET(0, &rfds);
- FD_SET(new_fd, &rfds);
- maxfd = new_fd;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
- perror("select");
- exit(EXIT_FAILURE);
- } else if (retval == 0) {
- continue;
- }
- else
- {
- if (FD_ISSET(0, &rfds))
- {
- bzero(buf, MAXBUF + 1);
- fgets(buf, MAXBUF, stdin);
- if (!strncasecmp(buf, "quit", 4)) {
- printf("i will quit!\n");
- break;
- }
- len = send(new_fd, buf, strlen(buf) - 1, 0);
- if (len > 0)
- printf ("send successful,%d byte send!\n",len);
- else {
- printf("send failure!");
- break;
- }
- }
- if (FD_ISSET(new_fd, &rfds))
- {
- bzero(buf, MAXBUF + 1);
- len = recv(new_fd, buf, MAXBUF, 0);
- if (len > 0)
- printf ("recv success :'%s',%dbyte recv\n", buf, len);
- else
- {
- if (len < 0)
- printf("recv failure\n");
- else
- {
- printf("the ohter one end ,quit\n");
- break;
- }
- }
- }
- }
- }
- close(new_fd);
- printf("need othe connecdt (no->quit)");
- fflush(stdout);
- bzero(buf, MAXBUF + 1);
- fgets(buf, MAXBUF, stdin);
- if (!strncasecmp(buf, "no", 2))
- {
- printf("quit!\n");
- break;
- }
- }
- close(sockfd);
- return 0;
- }
客户端代码
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <resolv.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #define MAXBUF 1024
- int main(int argc, char **argv)
- {
- int sockfd, len;
- struct sockaddr_in dest;
- char buffer[MAXBUF + 1];
- fd_set rfds;
- struct timeval tv;
- int retval, maxfd = -1;
- if (argc != 3)
- {
- printf("argv format errno,pls:\n\t\t%s IP port\n",argv[0], argv[0]);
- exit(EXIT_FAILURE);
- }
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("Socket");
- exit(EXIT_FAILURE);
- }
- bzero(&dest, sizeof(dest));
- dest.sin_family = AF_INET;
- dest.sin_port = htons(atoi(argv[2]));
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
- {
- perror(argv[1]);
- exit(EXIT_FAILURE);
- }
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
- {
- perror("Connect ");
- exit(EXIT_FAILURE);
- }
- printf("\nget ready pls chat\n");
- while (1)
- {
- FD_ZERO(&rfds);
- FD_SET(0, &rfds);
- FD_SET(sockfd, &rfds);
- maxfd = sockfd;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
- printf("select %s", strerror(errno));
- break;
- }
- else if (retval == 0)
- continue;
- else
- {
- if (FD_ISSET(sockfd, &rfds))
- {
- bzero(buffer, MAXBUF + 1);
- len = recv(sockfd, buffer, MAXBUF, 0);
- if (len > 0)
- printf ("recv message:'%s',%d byte recv\n",buffer, len);
- else
- {
- if (len < 0)
- printf ("message recv failure\n");
- else
- {
- printf("the othe quit ,quit\n");
- break;
- }
- }
- }
- if (FD_ISSET(0, &rfds))
- {
- bzero(buffer, MAXBUF + 1);
- fgets(buffer, MAXBUF, stdin);
- if (!strncasecmp(buffer, "quit", 4)) {
- printf("i will quit\n");
- break;
- }
- len = send(sockfd, buffer, strlen(buffer) - 1, 0);
- if (len < 0) {
- printf ("message send failure");
- break;
- } else
- printf
- ("send success,%d byte send\n",len);
- }
- }
- }
- close(sockfd);
- return 0;
- }
- $ ./tcp_sy_chat_server 172.18.229.62 8000
- ----wait for new connect
- server: got connection from 172.18.229.62, port 55410, socket 4
- recv success :'hello',5byte recv
- recv success :'test',4byte recv
- recv success :'why',3byte recv
- ready
- send successful,5 byte send!
- end
- send successful,3 byte send!
- quit
- i will quit!
- need othe connecdt (no->quit)no
- quit!
- $ ./tcp_sy_chat_client 172.18.229.62 8000
- get ready pls chat
- hello
- send success,5 byte send
- test
- send success,4 byte send
- why
- send success,3 byte send
- recv message:'ready',5 byte recv
- recv message:'end',3 byte recv
- the othe quit ,quit
原文链接