socket编程(九)
1.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模型
2.读,写,异常事件发生条件
1.可读
(1)套接口缓冲区数据可读
(2)连接的读一半关闭,即接收到FIN段,读操作将返回0
(3)如果是监听套接口,已完成连接队列不为空时
(4)套接口上发生了一个错误待处理,错误可以通过getsockopt指定SO_ERROR选项来获取
2.可写
(1)套接口发送缓冲区有空间容纳数据
(2)连接的写一半关闭。即收到RST段之后,再次调用write操作,
(3)套接口上发送了一个错误待处理,错误可以通过getsockopt指定SO_ERROR选项来获取。
3.异常
(1)套接口存在带外数据
3.用select改进回射服务器
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.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)/*param1:fd, param2:buf, param3:count
return:读取成功字节数
ssize_t:有符号
size_t:无符号*/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;
}/*
param1:fd, param2:buf, param3:count
return:已经发送了多少
*/
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;
}//从套接口接收数据,但是不从缓冲区中移除MSG_PEEK
//只要有偷看到数据就接收,没有头看到就是阻塞
//对方套接口关闭,返回0
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截止,最大不能超过maxline
ssize_t readline(int sockfd, void* buf, size_t maxline) {int ret;int nread;int nleft = maxline;char* bufp = (char*)buf;while(1) {//信号中断已在recv_peek中处理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 handle_sigchild(int sig) {//wait(NULL);//waitpid(-1, NULL, WNOHANG);while(waitpid(-1, NULL, WNOHANG) >0);
}int main () {//1.避免僵尸进程//signal(SIGCHLD, SIG_IGN);signal(SIGCHLD, handle_sigchild);int listenfd;if(( listenfd= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)//if((listenfd= socket(PF_INET, SOCK_STREAM, 0)) <0) ERR_EXIT("socket");struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//inet_aton("127.0.0.1", &servaddr.sin_addr);int on = 1;if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)ERR_EXIT("setsockopt");if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))<0)ERR_EXIT("bind");if(listen(listenfd, SOMAXCONN) < 0)ERR_EXIT("listen");struct sockaddr_in peeraddr;socklen_t peerlen = sizeof(peeraddr);int conn;int i;int client[FD_SETSIZE];int maxi = 0;for(i=0; i<FD_SETSIZE; i++) {client[i] = -1;}int nready;int maxfd = listenfd;fd_set rset;fd_set allset;FD_ZERO(&rset);FD_ZERO(&allset);FD_SET(listenfd, &allset);while(1) {rset = allset;nready = select(maxfd+1, &rset, NULL, NULL, NULL); if(nready == -1) { if(errno == EINTR)continue;ERR_EXIT("select");}if(nready == 0)continue;if(FD_ISSET(listenfd, &rset)) {peerlen = sizeof(peeraddr);conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);if(-1 == conn) {ERR_EXIT("accept");}for(i=0; i<FD_SETSIZE; i++) {if(client[i] < 0) {client[i] = conn;if(i > maxi) maxi = i;break;}}if( FD_SETSIZE == i) {fprintf(stderr, "too many client\n");exit(EXIT_FAILURE);}printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));FD_SET(conn, &allset);if(maxfd < conn) maxfd = conn;if(--nready == 0) continue;}for(i=0; i<=maxi; i++) {conn = client[i];if(-1 == conn)continue;if(FD_ISSET(conn, &rset)) {char recvbuf[1024] = {0};int ret = readline(conn, recvbuf, 1024);if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("client close\n");FD_CLR(conn, &allset);client[i] = -1;
close(conn);
}fputs(recvbuf, stdout);writen(conn, recvbuf, strlen(recvbuf));if(--nready == 0) break;}}}return 0;
}
socket编程(九)相关推荐
- python基础之socket编程
阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现象 ...
- Socket编程原理概述
1 问题的引入 UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close).在一个用户进程进行I/O操作时, ...
- python网络编程-socket编程
一.服务端和客户端 BS架构 (腾讯通软件:server+client) CS架构 (web网站) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 二.OSI七层模 ...
- 不为人知的网络编程(九):理论联系实际,全方位深入理解DNS
本文原作者:selfboot,博客地址:selfboot.cn,Github地址:github.com/selfboot,感谢原作者的技术分享. 1.引言 对于 DNS(Domain Name Sys ...
- Windows Socket编程笔记之最简单的小Demo
Windows Socket编程的大致过程: 服务器端: ----过程-------------对应的API------- 0.初始化 | WSAStartup() 1.创建So ...
- Linux下Socket编程
Linux下Socket编程 网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符.Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的S ...
- [Python_7] Python Socket 编程
0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*-"&qu ...
- C# Socket编程(5)使用TCP Socket
TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...
- 【.Net MF网络开发板研究-04】Socket编程之服务端
前几篇文章介绍了Http相关的应用,其实从技术角度而言,应该先介绍Socket编程,然后再介绍Http,毕竟Http是用Socket相关函数编程实现的. .NET Micro Framework的So ...
- socket编程缓冲区大小对send()的影响
1. 概述 Socket编程中,使用send()传送数据时,返回结果受到以下几个因素的影响: • Blocking模式或non-blocking模式 • 发送缓冲区的大小 • 接收窗口大小 本文档介绍 ...
最新文章
- python编程软件v-Python编程狮
- 结构体指针和数组理解
- linux安装 java jdk
- PIC单片机入门_PICC头文件介绍
- 自然语言处理python进阶(二)
- uitextfield 键盘类型_iOS输入类型-文本字段(Text Fields) | 菜鸟教程
- 文件上传命令rz和下载命令sz的安装
- Android培训翻译_使你的程序感知位置
- 2018最有用的六个机器学习项目
- Linux crontab 定时任务命令详解
- 让一个从未接触过电脑的人测试浏览器
- ICPC North Central NA Contest 2017 B - Pokemon Go Go
- python---pass和continue和break和exit()区别
- 电路基础和电路模拟——复习
- 路线规划算法设计要点
- 微信 css area,微信小程序--手写一个地区选择器(多级联动)
- Oralce性能优化-绑定变量窥视
- realme真我Q5和iQOOz6pro哪个值得买 两者配置对比
- SAP BP 业务实践与ABAP 分享
- influxdb连续查询