当前位置:首页 >> 机械/仪表 >>

Socket 知识


Socket 知识
阻 塞 描 述 符 ( 有 文 件 描 述 符 和 Socket 描 述 符 ) 。 调 用 函 数 (read/write/recv/recvfrom/recvmsg)返回的时间。非阻塞是不管有没有数据, 马上返回。阻塞是要等到有数据的时候再返回。Linux/Unix/Windows 默认都是 阻塞的。 (1)在 Unix 类系统设置 设置非阻塞:

int flags = fcntl(sockfd,F_GETFL) | O_NONBLOCK; fcntl(sockfd,F_SETFL,flags);

设置阻塞: int flags = fcntl(sockfd,F_GETFL) & (~ O_NONBLOCK); fcntl(sockfd,F_SETFL,flags);

(2)在 Windows 中设置 设置非阻塞 unsigned long isBlocked = 1; ioctlsocket(s, FIONBIO, (unsigned long*)&isBlocked); 设置阻塞 unsigned long isBlocked = 0; ioctlsocket(s, FIONBIO, (unsigned long*)&isBlocked);

2. Socket 常用选项配置。 int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); socket 选项对应表 level optname optval type SOL_SOCKET SO_RCVBUF/ SO_SNDBUF int 设置 socket 接受发送数据缓冲区大小,单位是字节。如果不希望系统用发送缓冲区, 即在调用 send/sendto 之后,直接发送数据,可设置 size = 0; int size = 32 * 1024; // 32KB. setsockopt(sockfd, SOL_SOCKET,SO_RCVBUF, &size, sizeof(size));

setsockopt(sockfd, SOL_SOCKET,SO_SNDBUF, &size, sizeof(size)); SOL_SOCKET SO_RCVTIMEO/ SO_SNDTIMEO struct timeval 设置 socket 接收发送数据超时. struct timeval tm = {0}; tm.tv_sec = N; // N seconds. tm.tv_usec = M_us; //N us. 1000000us = 1s setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)); SOL_SOCKET SO_REUSEADD/ SO_REUSEPORT int(逻辑布尔) SO_REUSEADDR 可以用在以下四种情况下。(摘自《Unix 网络编程》卷一,即 UNPv1) (1)、当有一个有相同本地地址和端口的 socket1处于 TIME_WAIT 状态时,而你启动的程序的 socket2要占用该地址和端口,你的程序就要用到该选项。 (2)、SO_REUSEADDR 允许同一 port 上启动同一服务器的多个实例(多个进程)。但每个实例绑定的 IP 地址是不能相同的。在有多块网卡或用 IP Alias 技术的机器可以测试这种情况。 (3)、SO_REUSEADDR 允许单个进程绑定相同的端口到多个 socket 上,但每个 socket 绑定的 ip 地 址不同。这和2很相似,区别请看 UNPv1。 (4)、 SO_REUSEADDR 允许完全相同的地址和端口的重复绑定。 但这只用于 UDP 的多播, 不用于 TCP。 只考虑 AF_INET 的情况(同一端口指 ip 地址与端口号都相同) 1.freebsd 支持 SO_REUSEPORT 和 SO_REUSEADDR 选项,而 linux 只支持 SO_REUSEADDR 选项。 2.freebsd 下,使用 SO_REUSEPORT 选项,两个 tcp 的 socket 可以绑定同一个端口;同样,使用 SO_REUSEPORT 选项,两个 udp 的 socket 可以绑定同一个端口。 3.linux 下,两个 tcp 的 socket 不能绑定同一个端口;而如果使用 SO_REUSEADDR 选项,两个 udp 的 socket 可以绑定同一个端口。 4.freebsd 下,两个 tcp 的 socket 绑定同一端口,只有第一个 socket 获得数据。 5.freebsd 下,两个 udp 的 socket 绑定同一端口,如果数据包的目的地址是单播地址,则只有第 一个 socket 获得数据,而如果数据包的目的地址是多播地址,则两个 socket 同时获得相同的数 据。 6.linux 下,两个 udp 的 socket 绑定同一端口,如果数据包的目的地址是单播地址,则只有最后 一个 socket 获得数据,而如果数据包的目的地址是多播地址,则两个 socket 同时获得相同的数 据。 有些系统如 Linux,没有定义 SO_REUSEPORT,可自行加上。 #define SO_REUSEPORT 15 ) int usable = 1; setsockopt(sockfd, SOL_SOCKET ,SO_REUSEADDR, &usable , sizeof(usable )); setsockopt(sockfd, SOL_SOCKET ,SO_REUSEPORT, &usable , sizeof(usable )); SOL_SOCKET SO_BROADCAST (一般用于 UDP.) int(逻辑布尔) 希望该 socket 发送的数据具有广播特性。 int bBroadcast= 1; setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &bBroadcast, sizeof(BOOL)); struct linger { SOL_SOCKET SO_LINGER u_short l_onoff; //linger 开关

u_short l_linger; //等待时间,单位:秒}; 延缓面向连接的 socket 的 close 操作。默认,close 立即返回,但是当发送缓冲区中还有一部分 数据的时候,系统将会尝试将数据发送给对端。SO_LINGER 可以改变 close 的行为,即处于连接 状态的 soket 在调用 close socket 后强制关闭,不经历 TIME_WAIT(TCP)的过程。这个选项需要 谨慎使用,尤其是强制式关闭,会丢失服务器发给客户端的最后一部分数据。

struct linger llinger = {1, 5}; //1:打开 linger 选项,停留时间为5秒 setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&llinger,sizeof(llinger)); SOL_SOCKET SO_DONTLINGER int(逻辑布尔) 如果要已经处于连接状态的 soket 在调用 close socket 后强制关闭,不经历 TIME_WAIT 的过程。 setsockopt(s,SOL_SOCKET,SO_DONTLINGER,&bDontLinger,sizeof(int)); SOL_SOCKET SO_CONDITIONAL_ACCEPT int(逻辑布尔) 在 client 连接服务器过程中,如果处于非阻塞模式下的 socket 在 connect()的过程中可以设置 connect()延时,直到 accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的作用,在阻塞 的函数调用中作用不大)

int bConditionalAccept=1; setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,&bConditionalAccept,sizeof(int )); SOL_SOCKET SO_KEEPALIVE int(bool) IPPROTO_TCP TCP_KEEPCNT int IPPROTO_TCP TCP_KEEPIDLE int(单位:500ms) IPPROTO_TCP TCP_KEEPINTVL int(单位:500ms) 如果一方已经关闭或异常终止连接,而另一方却不知道,我们将这样的 TCP 连接称为半打开的。 TCP 通过保活定时器(KeepAlive)来检测半打开连 接。在高并发的网络服务器中,经常会出现漏 掉 socket 的情况,对应的结果有一种情况就是出现大量的 CLOSE_WAIT 状态的连接。这个时候, 可以通 过设置 KEEPALIVE 选项来解决这个问题。设置 SO_KEEPALIVE 选项来开启 KEEPALIVE,然 后通过 TCP_KEEPIDLE、 TCP_KEEPINTVL 和 TCP_KEEPCNT 设置 keepalive 的开始时间、 间隔、 次数。 也 可 通 过 /proc/sys/net/ipv4/tcp_keepalive_time 、 tcp_keepalive_intvl 和 tcp_keepalive_probes 修改,只是是整个系统都会随之改变。 TCP_KEEPCNT: 关闭一个非活跃连接之前进行探测的最大次数。默认为 8 次 TCP_KEEPINTVL:两个探测的时间间隔,默认值为 150 即 75 秒。 TCP_KEEPIDLE: 对一个连接进行有效性探测之前运行的最大非活跃时间间隔, 默认值为 14400 (即 2 个小时) 。 int keepalive = 1; //开启 keepalive setsockopt(incomingsock,SOL_SOCKET, SO_KEEPALIVE,&keepalive, sizeof(keepalive)); int max_idle_time = 28800; //当 socket 处于 IDLE 时,4小时内要有真实数据通信. setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE,&start_time ,sizeof(int)); int interval = 300; //间隔时间为150秒, 每150秒心跳一次。 setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, &interval , sizeof(interval));

int probes= 8; //最大探测次数为8 setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, &probes, sizeof(probes)); IPPROTO_TCP TCP_NODELAY/ TCP_CHORK int(逻辑布尔) TCP_NODELAY 不使用 Nagle 算法, 不会将小包进行拼接成大包再进行发送, 直接将小包发送出去, 会使得小包时候用户体验非常好。 当在传送大量数据的时候,为了提高 TCP 发送效率,可以设置 TCP_CORK,CORK 顾名思义,就是" 塞子"的意思,它会尽量在每次发送最大的数据量。当设置了 TCP_CORK 后,会有阻塞200ms,当阻 塞时间过后,数据就会自动传送。也是禁用了 Nagle 化。

# int enable = 1; setsockopt(s,IPPROTO_TCP,TCP_NODELAY, &enable,sizeof(enable)); setsockopt(s,IPPROTO_TCP,TCP_CHORK, &enable,sizeof(enable)); IPPROTO_TCP TCP_DEFER_ACCEPT int(单位:秒) 推迟 accept,实际上是当接收到第一个数据之后,才会创建连接。kernel 在到达设置的秒数以后还没有收到 数据,不会继续唤醒进程,而是直接丢弃连接。如果服务器设置 TCP_DEFER_ACCEPT 选项后,服务 器受到一个 CONNECT 请求后,三次握手之后,新的 socket 状态依然为 SYN_RECV,而不是 ESTABLISHED,操作系统不会 Accept。 由于设置 TCP_DEFER_ACCEPT 选项之后,三次握手后状态没有达到 ESTABLISHED,而是 SYN_RECV。 这个时候,如果客户端一直没 有发送"数据"报文,服务器将重传 SYN/ACK 报文,重传次数受 net.ipv4.tcp_synack_retries 参数控制,达到重传次数之后, 才会再次进行 setsockopt 中设 置的超时值,因此会出现 SYN_RECV 生存时间比设置值大一些的情况。 int max_seconds = 5; setsockopt(s, TCP_DEFER_ACCEPT, &max_seconds , sizeof(max_seconds )); IPPROTO_IP IP_HDRINCL int(逻辑布尔) 设置混杂模式。读数据的时候,连 IP 头一起在缓冲区里面,sendto 的时候,要自己设置 IP 头。 一般用于 SOCK_RAW. char buffer[PCKT_LEN]; struct ipheader *iphdr = (struct ipheader *) buffer; struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader)); int flag = 1; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(int)); recvfrom(sockfd, buffer, &len, 0, &addr, &addr_eln); iphdr->.....; sendto(sockfd, buffer, &len, 0, &addr, addr_eln); IPPROTO_IP IP_TOS 一般不用。部分系统不支持。 IPPROTO_IP IP_TTL 一般不用。部分系统不支持。

int(逻辑布尔) int(逻辑布尔)

IPPROTO_IP IP_OPTINOS 一般不用。部分系统不支持。

int(逻辑布尔)

3. 判断对方 TCP socket / UDP socket bound destination address 是否关闭。 if(recv(sockfd, buf, 100) == 0) { ...... } 4. linux/epoll 函数. ET / LT 工作模式: ET 模式仅当状态发生变化的时候才获得通知,这里所谓的状态的变化并不包括 缓 冲 区 中 还 有 未 处 理 的 数 据 , 也 就 是 说 , 如 果 要 采 用 ET 模 式 , 需 要 一 直 read/write 直到出错为止,很多人反映为什么采用 ET 模式只接收了一部分数据 就再也得不到通知了,大多因为这样;而 LT 模式是只要有数据没有处理 就会一 直通知下去的. #include int epoll_create(int maxfdnum); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); int close(int epfd);

epfd: 是 epoll_create 返回的描述符。 op: EPOLL_CTL_ADD / EPOLL_CTL_MOD / EPOLL_CTL_DEL fd: 要操作的描述符(这里就是 socket 号)。 event: struct epoll_event { __uint32_t events; epoll_data_t data; }; events 可以是以下几个宏的集合: EPOLLIN :表示对应的文件描述符可以读(包括对 端 SOCKET 正常关闭) ; EPOLLOUT:表示对应的文件描述符可以写; EPOLLPRI:表示对应的文件描述符有紧急的数据可 读(这里应该表示有带外数据到来) ; EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET:将 EPOLL 设为边缘触发(Edge Triggered) 模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事 件之后, 如果还需要继续监听这个 socket 的话,需要再次把这个 socket 加入到 EPOLL 队列里 maxevents: 必须小于等于 maxfdnum。是监听的最大事件数。 events: 其实类型是 struct epoll_event events[]. IN, 要监听的事件集合。 OUT, 发生事件的集合。 返回值是 集合的个数。 当返回 0 为超 时,表示没有感兴趣的事件发生。 timeout: 超时时间,单位是毫秒。 -1为无限的不确定的等待。可以理解为阻塞 的意思。

int count = epoll_wait(epfd, event, 12, -1); int index = 0; for(index = 0; index < count; index++) { event[index].fd; //这个就是 socket 套接字。 ......... }

5. 增加最大描述符数。 我们都知道,通常一个终端下最多只能有1024个描述符, 还有0,1,2默认被占用,加上设备/文件,有时候还真的不够用。怎么增加呢? 软限制/硬限制: 软限制是指内核所能支持的资源上限 。硬限制只是作为软限制的上 限。软限制不能超过硬限制。 命令设置: ulimit -n ulimit -n 10000 关闭当前终端配置将自动失效。 编程设置:getrlimit,setrlimit/ RLIMIT_NOFILE #include #include #include int getrlimit(int resource, struct rlimit *rlp); int setrlimit(int resource, const struct rlimit *rlp); int fun(int max) { struct rlimit limit = {0}; getrlimit(RLIMIT_NOFILE, &limit );

limit.rlim_cur =

limit.rlim_max;

limit.rlim_max = max; setrlimit(RLIMIT_NOFILE, &limit ); return 0; }

另外,还有 RLIMIT_CPU / RLIMIT_STACK / RLIMIT_NPROC.


相关文章:
IC测试socket基础知识
IC测试socket基础知识_信息与通信_工程科技_专业资料。IC测试socket基础知识Socket 是广大测试工程师所经常用到测试夹具,它的好坏直接关系到调试的进度,量产测 试的成...
socket网络编程的一些基础知识
socket网络编程的一些基础知识_信息与通信_工程科技_专业资料。socket网络编程的一些基础知识 socket 网络编程的一些基础知识 目录: 1) 什么是套接字? 2) Internet...
socket 知识
socket 7页 1财富值如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 socket 知识 socket 知识socket 知识隐藏>> 网络编程...
socket知识介绍
socket知识介绍socket知识介绍隐藏>> 一、socket 知识介绍 1.阻断型和非阻断型端口. 1.阻断型和非阻断型端口. 阻断型和非阻断型端口 阻断型(stThreadBlocking) (...
Socket知识整理
Socket知识整理 整理的关于Socket知识,供初学者参考整理的关于Socket知识,供初学者参考隐藏>> TCP/IP 体系结构、特点及相关术语 体系结构、一、TCP/IP 体系结构...
Socket原理与编程基础
介绍完基础知识,下面就介绍一些 API 函数: 创建套接字──socket() 应用程序在使用套接字前,首先必须拥有一个套接字,系统调用 socket()向应用程序提供创建套接...
Socket编程回顾--套接字编程基础
Socket编程回顾--套接字编程基础_电脑基础知识_IT/计算机_专业资料。Socket 编程回顾(1)--套接字编程基础套接字,英文为 socket,是一种双向的通信端口。位于网络...
soket基础知识
soket基础知识_计算机硬件及网络_IT/计算机_专业资料。soket基础知识WinSock 基本知识 这里不打算系统地介绍 socket 或者 WinSock 的知识。首先介绍 WinSock API 函数,...
网络程序设计 socket 复习题 考点 知识点
IOS Socket 通讯相关知识... 5页 免费 网络程序设计基础复习题 5页 免费 网络编程复习题 15页 免费网​络​程​序​设​计​ ​s​o​c​...
网络socket一些知识
失败时返回 SOCKET_ERROR 第六章 Socket 函数说明 6.1 库函数综述 6.1.1 套接字函数表 6.1 Windows Sockets 1.1 版本的 Berkeley Sockets 函数 确认外来...
更多相关标签:
socket | websocket | socket.io | socket编程 | java socket编程 | c socket | websocket 教程 | java socket |