socket编程(八)
来源:互联网 发布:剑网三捏脸数据非法 编辑:程序博客网 时间:2024/06/04 00:54
1.五种I/O模型
1.阻塞I/O
2.非阻塞I/O
fcntl(fd, F_SETFL, flag|O_NONBLOCK);
忙等待,不推荐使用
3.I/O复用
4.信号驱动I/O
信号通知,有数据到来。应用进程通过信号处理程序中,调用recv函数,从内核空间拉到用户空间中。
5.异步I/O
信号接收到数据,推送到buf中。2.select
int select (int nfds, fd_set* readfds, fd_set* writefds, fd_set* excepts, struct timeval* timeout);
void FD_CLR(int fd, fd_set* set);
int FD_ISSET(int fd, fd_set* set);
void FD_SET(int fd, fd_set* set);
void FD_ZERO(fd_set* set);
Select管理者
用select来管理多个I/O。一旦其中的一个或者多个I/O检测到我们所感兴趣的事件。
Select函数返回,返回值为检测到的事件个数
并且返回哪些I/O发生了事件
遍历这些事件,进而处理事件
param:
1. 读,写,异常集合中的文件描述符的最大值+1
2. 读集合
3. 写集合
4. 异常集合
5. 超时结构体3.select改进回射客户端
(1)多个I/O,单进程处理
(2)服务端关闭与客户端的子进程,服务端等待到客户端read返回0;否则需要stdin输入。这样可以同时处理输入I/O,套接字I/O。
(3)标准输入I/O,网络I/O。同时检测这两种事件
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) ssize_t readn(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nread; //已经读了char* bufp = (char*)buf;while(nleft > 0) {if((nread = read(fd, bufp, nleft)) < 0) {if(errno == EINTR) continue;return -1;} else if (0 == nread) {return count - nleft;}bufp += nread;nleft -= nread;}return count;}ssize_t writen(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nwrite;char* bufp = (char*)buf;while(nleft > 0) {if((nwrite = write(fd, bufp, nleft)) < 0) {if(errno == EINTR)continue;return -1;} else if(0 == nwrite) {continue;}bufp += nwrite;nleft -= nwrite;}return count;}ssize_t recv_peek(int sockfd, void* buf, size_t len) {while(1) {int ret = recv(sockfd, buf, len, MSG_PEEK);if(-1 == ret && errno == EINTR) continue;return ret;}}//读取遇到\r\n截止,最大不能超过maxlinessize_t readline(int sockfd, void* buf, size_t maxline) {int ret;int nread;char* bufp = (char*)buf;int nleft = maxline;while(1) {ret = recv_peek(sockfd, bufp, nleft);if(ret < 0) //信号中断 return ret;if(0 == ret) //表示对方关闭套接口 return ret;nread = ret;int i;//该缓冲区中有\n,read读走for(i=0; i<nread; i++) {if(bufp[i] == '\n') {ret = readn(sockfd, bufp, i+1); //包括\n都读走if(ret != i+1) exit(EXIT_FAILURE);return ret;}}//没有\n,read先读走这部分,然后bufp偏移if(nread > nleft) exit(EXIT_FAILURE);nleft -= nread;ret = readn(sockfd, bufp, nread); if(ret != nread) exit(EXIT_FAILURE);bufp += nread;}return -1;}void echo_cli(int sock) {/* char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; int n; while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) {//将带有\n的buf发送过去 //writen(sock, sendbuf, strlen(sendbuf)); //TCP协议栈收到FIN报文writen(sock, sendbuf, 1);//TCP协议栈收到RST报文writen(sock, sendbuf+1, strlen(sendbuf)-1);//第二次发送后,会产生SIGPIPE信号 int ret = readline(sock, recvbuf, sizeof(recvbuf));if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("client close\n");break;} fputs(recvbuf, stdout); memset(sendbuf, 0, sizeof(sendbuf)); memset(recvbuf, 0, sizeof(recvbuf)); } close(sock);*/fd_set rset;FD_ZERO(&rset);int nready;int maxfd;int fd_stdin = fileno(stdin);if(fd_stdin > sock) maxfd = fd_stdin;elsemaxfd = sock; char sendbuf[1024] = {0}; char recvbuf[1024] = {0};while(1) {FD_SET(fd_stdin, &rset);FD_SET(sock, &rset);nready = select(maxfd+1, &rset, NULL, NULL, NULL);if(-1 == nready) ERR_EXIT("select");if(0 == nready) continue;if(FD_ISSET(sock, &rset)) {int ret = readline(sock, recvbuf, sizeof(recvbuf));if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("server close\n");break;}fputs(recvbuf, stdout);memset(sendbuf, 0, sizeof(sendbuf));memset(recvbuf, 0, sizeof(recvbuf));}if(FD_ISSET(fd_stdin, &rset)) {if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)break;writen(sock, sendbuf, strlen(sendbuf));memset(sendbuf, 0, sizeof(sendbuf));}}close(sock);}void handle_sigpipe(int sig) {printf("recv a sig=%d\n", sig); }int main () {//signal(SIGPIPE, handle_sigpipe);signal(SIGPIPE, SIG_IGN); int sock;if(( sock= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) ERR_EXIT("socket"); sock = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("sockect"); //获得本端ip,portstruct sockaddr_in localaddr;socklen_t addrlen= sizeof(localaddr);if(getsockname(sock,(struct sockaddr*)&localaddr, &addrlen) < 0)ERR_EXIT("getsockname");printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));struct sockaddr_in connaddr;socklen_t connlen = sizeof(connaddr);//通过getpeername得到对端addr,port[conn必须是已连接的套接字]getpeername(sock, (struct sockaddr*)&connaddr, &connlen);printf("ip=%s port=%d\n", inet_ntoa(connaddr.sin_addr), ntohs(connaddr.sin_port)); echo_cli(sock); return 0;}
阅读全文
1 0
- socket编程(八)
- socket编程原理(八)
- socket编程总结(八)bind()
- python(八)socket网络编程
- Linux Socket学习(八)
- Linux Socket学习(八)
- linux网络编程之socket(八):五种I/O模型和select函数简介
- linux网络编程之socket(八):五种I/O模型和select函数简介
- linux网络编程之socket(八):五种I/O模型和select函数简介
- linux网络编程之socket(八):五种I/O模型和select函数简介
- 编程作业(八)
- Python学习笔记(八) -- Python Socket 编程 - 聊天室示例程序
- Linux下的socket编程实践(八) Select的限制和poll(并发的初步知识)
- java网络socket编程(八)之java中BIO实现聊天系统的群聊功能
- C/C++ socket编程教程之八:socket缓冲区和阻塞模式
- C专家编程(八)
- 《Python编程》笔记(八)
- C编程(八)数组
- springmvc搭建
- 大端存储与小端存储
- 离屏渲染FBO中使用depth信息
- 虚拟机连接CentOS,CentOS安装Redis
- 简单几步为Atom配置LaTex插件支持数学公式
- socket编程(八)
- ORACLE rollup函数的使用(与group by一起使用)
- C++输出格式
- 点击多个按钮之间互不影响(自定义属性)
- JRTPLIB使用实例
- 修ITI.Transcendata.CADFIX.v11.SP1-ISO 1DVD
- spawn类发送与获取信息方法详解
- 分布式服务框架 Zookeeper -- 管理分布式环境中的数据
- TensorFlow大本营