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编程(九)相关推荐

  1. python基础之socket编程

    阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现象 ...

  2. Socket编程原理概述

    1 问题的引入  UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close).在一个用户进程进行I/O操作时, ...

  3. python网络编程-socket编程

    一.服务端和客户端 BS架构 (腾讯通软件:server+client) CS架构 (web网站) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 二.OSI七层模 ...

  4. 不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

    本文原作者:selfboot,博客地址:selfboot.cn,Github地址:github.com/selfboot,感谢原作者的技术分享. 1.引言 对于 DNS(Domain Name Sys ...

  5. Windows Socket编程笔记之最简单的小Demo

    Windows Socket编程的大致过程: 服务器端: ----过程-------------对应的API-------  0.初始化         |  WSAStartup()  1.创建So ...

  6. Linux下Socket编程

    Linux下Socket编程    网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符.Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的S ...

  7. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*-"&qu ...

  8. C# Socket编程(5)使用TCP Socket

    TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...

  9. 【.Net MF网络开发板研究-04】Socket编程之服务端

    前几篇文章介绍了Http相关的应用,其实从技术角度而言,应该先介绍Socket编程,然后再介绍Http,毕竟Http是用Socket相关函数编程实现的. .NET Micro Framework的So ...

  10. socket编程缓冲区大小对send()的影响

    1. 概述 Socket编程中,使用send()传送数据时,返回结果受到以下几个因素的影响: • Blocking模式或non-blocking模式 • 发送缓冲区的大小 • 接收窗口大小 本文档介绍 ...

最新文章

  1. python编程软件v-Python编程狮
  2. 结构体指针和数组理解
  3. linux安装 java jdk
  4. PIC单片机入门_PICC头文件介绍
  5. 自然语言处理python进阶(二)
  6. uitextfield 键盘类型_iOS输入类型-文本字段(Text Fields) | 菜鸟教程
  7. 文件上传命令rz和下载命令sz的安装
  8. Android培训翻译_使你的程序感知位置
  9. 2018最有用的六个机器学习项目
  10. Linux crontab 定时任务命令详解
  11. 让一个从未接触过电脑的人测试浏览器
  12. ICPC North Central NA Contest 2017 B - Pokemon Go Go
  13. python---pass和continue和break和exit()区别
  14. 电路基础和电路模拟——复习
  15. 路线规划算法设计要点
  16. 微信 css area,微信小程序--手写一个地区选择器(多级联动)
  17. Oralce性能优化-绑定变量窥视
  18. realme真我Q5和iQOOz6pro哪个值得买 两者配置对比
  19. SAP BP 业务实践与ABAP 分享
  20. influxdb连续查询

热门文章

  1. C Primer Plus 第8章 字符输入/输出和输入确认 8.11 编程练习答案
  2. 使用shell测试cdn状态
  3. 关于单页面应用一些随想
  4. 黑苹果无法登录Appstore
  5. (转)asp.net夜话之十一:web.config详解
  6. CVTE 2017 秋季校招一面(C++ 后台)
  7. python学习之字符串函数用法
  8. Akka源码分析-Akka Typed
  9. 如何解决代码嵌套太深问题
  10. PHP中提问频率最高的11个面试题和答案