《TCP/IP网络编程》(第九章)套接字的多种选项

2024-05-24 10:52

本文主要是介绍《TCP/IP网络编程》(第九章)套接字的多种选项,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.套接字的多种可选项

在这里插入图片描述
SOL_SOCKET的选项是套接字相关的选项
IPPROTO_IP的可选项是IP协议相关的选项
IPPROTO_TCP的可选项是TCP协议相关的选项

接下来会简单介绍几个选项和用法

2.对选项信息进行读取和设置

使用getsockopt()setsockopt()进行读取和设置,语法如下:

Linux系统
getsockopt()读取套接字选项

int getsockopt(
int sockfd,           //sockfd:要查看的套接字的文件描述符。
int level,            //level:要查看的协议层,如SOL_SOCKET。
int optname,          //要查询的选项的名称。
void *optval,         //指向一个缓冲区,该缓冲区将接收查询的选项值。
socklen_t *optlen     //向optval缓冲区传递的缓冲大小。调用成功后,它会被设置为选项值的实际长度。
);  

setsockopt()设置套接字选项

int setsockopt(
int sockfd,            //sockfd:要设置的套接字文件描述符。
int level,             //level:要设置的协议层,如SOL_SOCKET。
int optname,           //optname:要设置的选项的名称。
const void *optval,    //optval:指向包含要设置的选项值的缓冲区。
socklen_t optlen       //optval缓冲区的长度。
);

Windows系统
getsockopt()读取套接字选项

int getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen
);

setsockopt()设置套接字选项

int getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen
);

3.SOL_SOCKET协议层中的SO_SNDBUFSO_RCVBUF

前者是输入缓冲大小的相关选项,后者是输出缓冲大小的相关选项
Linux系统

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
void error_handling(const char *message);int main(int argc, char *argv[]){int sock;int result;// 用于存储函数调用结果socklen_t optlen;// 用于存储选项长度int recvBufSize, sendBufSize;// 用于存储接收和发送缓冲区大小int buffer_value = 1024; // 我们想要设置的缓冲区大小// 创建套接字(示例中使用IPv4 TCP套接字)sock = socket(AF_INET, SOCK_STREAM, 0);if (!sock) {error_handling(" sock buliding error");return 1;}// 获取默认的接收缓冲区大小optlen = sizeof(recvBufSize);result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufSize, &optlen);if (result) {error_handling("getsockopt SO_RCVBUF error");} else {printf("Default receive buffer size: %d\n", recvBufSize);}// 获取默认的发送缓冲区大小result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, &optlen);if (result) {error_handling("getsockopt SO_SNDBUF error");} else {printf("Default send buffer size: %d\n", sendBufSize);}// 设置接收缓冲区大小为1024result = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char*)&buffer_value, sizeof(buffer_value));if (result) {error_handling("setsockopt SO_RCVBUF error");} else {// 验证接收缓冲区大小设置result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufSize, &optlen);if (result) {error_handling("get new SO_RCVBUF error");} else {printf("New receive buffer size: %d\n", recvBufSize);}}// 设置发送缓冲区大小为1024result = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&buffer_value, sizeof(buffer_value));if (result) {error_handling("setsockopt SO_SNDBUF error");} else {// 验证发送缓冲区大小设置result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, &optlen);if (result) {error_handling("get new SO_SNDBUF error");} else {printf("New send buffer size: %d\n", sendBufSize);}}return 0;}void error_handling(const char *msg){fputs(msg, stderr);fputc('\n', stderr);exit(1);
}

在这里插入图片描述

输出的结果和我们预设的不同,受限于系统,可能无法按照我们的要求100%实现,操作系统可能有自己的缓冲区大小限制,这些限制可能高于或低于您尝试设置的值。如果设置的值超出了系统允许的范围,系统会自动调整到允许的最大或最小值。
Windows系统

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>int main() {WSADATA wsaData;SOCKET sock = INVALID_SOCKET;int result;// 用于存储函数调用结果socklen_t optlen;// 用于存储选项长度int recvBufSize, sendBufSize;// 用于存储接收和发送缓冲区大小int buffer_value = 1024; // 我们想要设置的缓冲区大小// 初始化WinSockresult = WSAStartup(MAKEWORD(2,2), &wsaData);if (result != 0) {printf("WSAStartup failed: %d\n", result);return 1;}// 创建套接字(示例中使用IPv4 TCP套接字)sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sock == INVALID_SOCKET) {printf("Could not create socket: %ld\n", WSAGetLastError());WSACleanup();return 1;}// 获取默认的接收缓冲区大小optlen = sizeof(recvBufSize);result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufSize, &optlen);if (result == SOCKET_ERROR) {printf("getsockopt failed for SO_RCVBUF: %d\n", WSAGetLastError());} else {printf("Default receive buffer size: %d\n", recvBufSize);}// 获取默认的发送缓冲区大小result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, &optlen);if (result == SOCKET_ERROR) {printf("getsockopt failed for SO_SNDBUF: %d\n", WSAGetLastError());} else {printf("Default send buffer size: %d\n", sendBufSize);}// 设置接收缓冲区大小为1024result = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char*)&buffer_value, sizeof(buffer_value));if (result == SOCKET_ERROR) {printf("setsockopt failed for SO_RCVBUF: %d\n", WSAGetLastError());} else {// 验证接收缓冲区大小设置result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufSize, &optlen);if (result == SOCKET_ERROR) {printf("getsockopt failed for SO_RCVBUF: %d\n", WSAGetLastError());} else {printf("New receive buffer size: %d\n", recvBufSize);}}// 设置发送缓冲区大小为1024result = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&buffer_value, sizeof(buffer_value));if (result == SOCKET_ERROR) {printf("setsockopt failed for SO_SNDBUF: %d\n", WSAGetLastError());} else {// 验证发送缓冲区大小设置result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, &optlen);if (result == SOCKET_ERROR) {printf("getsockopt failed for SO_SNDBUF: %d\n", WSAGetLastError());} else {printf("New send buffer size: %d\n", sendBufSize);}}// 清理资源closesocket(sock);WSACleanup();system("pause");return 0;
}

在这里插入图片描述

4.Time-wait状态

在基于TCP的服务器端/客户端(2)中讲述“四次挥手的时,第四次挥手中,主动关闭方发送一个ACK作为回应,便会进入TIME_WAIT状态。
在这里插入图片描述
若没有TIME_WAIT状态,如果最后这条ACK消息在传输途中丢失了,未能传给主机B,则主机B就会重传FIN消息,而不是关闭连接,但此时主机A已经关闭连接无法收到消息,那么主机B将无法按照程序关闭连接。
但因为有TIME_WAIT状态,主机A就会收到重传的FIN消息,然后重新发送ACK消息给主机B,让主机B正常关闭连接。

但是TIME_WAIT状态也有缺点,如果需要尽快重启服务器,但因为网络不好,便会一直处于TIME_WAIT状态。
在这里插入图片描述
解决方法就是使用SO_REUSEADDR

5.SOL_SOCKET协议层中的SO_REUSEADDR

SO_REUSEADDR 是一个 socket 选项,允许一个 socket 绑定到一个已经在使用中的地址和端口上。当应用程序关闭处于 TIME_WAIT 状态的连接时,如果启用了 SO_REUSEADDR,新的 socket 可以立即重用该地址和端口,即使之前的连接仍在 TIME_WAIT 状态。
使用语法

int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval));

当服务器端添加了这个代码后,即让服务器处于SO_REUSEADDR状态,即使由于网络问题,导致服务器无法正常关闭,也可以立刻重新运行服务器程序,让服务器重新绑定在之前的地址和端口上。

6.Nagle算法

TCP套接字默认使用Nagle算法,下图是极端例子下使用和不使用Nagle算法:
在这里插入图片描述
左图是使用Nagle算法,右图是不使用Nagle算法,这里再次强调,即使是不使用Nagle算法,数据传输也不是逐字传输,这里只是方便理解,极端化处理。

Nagle算法优点:

  • 减少网络拥塞: 通过减少小包的数量,可以降低网络拥塞,特别是在高延迟网络中。
  • 提高带宽利用率: 通过发送更大的数据包,可以更有效地利用可用带宽。

Nagle算法缺点:

  • 增加交互式应用的延迟: 对于需要快速响应的交互式应用(如远程登录或在线游戏),Nagle算法可能会导致感知上的延迟,因为它延迟了小数据包的发送。
  • 与某些应用协议不兼容: 一些应用协议依赖于小数据包的快速传输,Nagle算法可能会干扰这些协议的正常工作。

为了解决这些问题,TCP提供了一个称为TCP_NODELAY的选项,允许禁用Nagle算法。如果应用程序需要发送小的、需要快速确认的数据包,可以设置这个选项来禁用Nagle算法,从而允许立即发送数据包,不进行合并。

7.IPPROTO_TCP协议层中的TCP_NODELAY

TCP_NODELAY 是一个用于控制 TCP 连接中 Nagle 算法行为的套接字选项。默认情况下,Nagle 算法通过合并小的数据包来减少网络拥塞和提高带宽利用率,但这可能会导致交互式应用的延迟增加。

当启用 TCP_NODELAY 选项时,它会禁用 Nagle 算法的合并过程,允许立即发送小的数据包,而不需要等待更多的数据来填满一个最大报文段(MSS)。这可以减少延迟,特别是在需要快速响应的应用中,如远程登录(SSH)、在线游戏或任何需要实时通信的场景。

启动TCP_NODELAY

int optval = 1;// 启用 TCP_NODELAY ,禁用 Nagle 算法
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&optval, sizeof(optval)) 

查看状态

int opt_val;
socklent_ opt_len;
opt_len=sizeof(opt_val);
getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, &opt_len)
//使用状态opt_val会保存为0,禁用状态则保存为1

这篇关于《TCP/IP网络编程》(第九章)套接字的多种选项的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/998200

相关文章

【Altium】查找PCB上未连接的网络

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标: PCB设计后期检查中找出没有连接的网络 应用场景:PCB设计后期,需要检查是否所有网络都已连接布线。虽然未连接的网络会有飞线显示,但是由于布线后期整板布线密度较高,虚连,断连的网络用肉眼难以轻易发现。用DRC检查也可以找出未连接的网络,如果PCB中DRC问题较多,查找起来就不是很方便。使用PCB Filter面板来达成目的相比DRC

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

16.Spring前世今生与Spring编程思想

1.1.课程目标 1、通过对本章内容的学习,可以掌握Spring的基本架构及各子模块之间的依赖关系。 2、 了解Spring的发展历史,启发思维。 3、 对 Spring形成一个整体的认识,为之后的深入学习做铺垫。 4、 通过对本章内容的学习,可以了解Spring版本升级的规律,从而应用到自己的系统升级版本命名。 5、Spring编程思想总结。 1.2.内容定位 Spring使用经验

通信系统网络架构_2.广域网网络架构

1.概述          通俗来讲,广域网是将分布于相比局域网络更广区域的计算机设备联接起来的网络。广域网由通信子网于资源子网组成。通信子网可以利用公用分组交换网、卫星通信网和无线分组交换网构建,将分布在不同地区的局域网或计算机系统互连起来,实现资源子网的共享。 2.网络组成          广域网属于多级网络,通常由骨干网、分布网、接入网组成。在网络规模较小时,可仅由骨干网和接入网组成

(超详细)YOLOV7改进-Soft-NMS(支持多种IoU变种选择)

1.在until/general.py文件最后加上下面代码 2.在general.py里面找到这代码,修改这两个地方 3.之后直接运行即可

Toolbar+DrawerLayout使用详情结合网络各大神

最近也想搞下toolbar+drawerlayout的使用。结合网络上各大神的杰作,我把大部分的内容效果都完成了遍。现在记录下各个功能效果的实现以及一些细节注意点。 这图弹出两个菜单内容都是仿QQ界面的选项。左边一个是drawerlayout的弹窗。右边是toolbar的popup弹窗。 开始实现步骤详情: 1.创建toolbar布局跟drawerlayout布局 <?xml vers

[vivado][IP核]FFT

刘东华的IP核详解: 1、 2、

[vivado][IP核]DDS

刘东华的IP核详解: 1、 这里的是指IP核配置中的相位数据的宽度。 2、 实际使用此IP核时并没有“频率分辨率”可以配,是靠改变来变的。 3、 4、 5、 数据输出的ready在数据正式输出时才会有。 自己仿真: 使用SIN/COS LUT only的模式,使用一个累加器作为相位输入,不知怎么,输出为X。

[ip核][vivado]aurora

Xapp1193:  discovered:1)并不是所有芯片都支持aurora.xc7z010就没有。                     2)XDC文件的指令-允许未约束的引脚的存在:                 set_property BITSTREAM.General.UnconstrainedPins {Allow} [current_design] PG046

[ip核][vivado]Block Menory Gennerator 学习

<刘东华的xilinx系列FPGA芯片IP核详解>读书摘录: 1. 2. 3.