LINUX C 的TCP发送接收测试

本文详细介绍了TCP协议下使用C语言进行套接字编程,包括客户端和服务器端的代码实现,涉及socket、read、write、pthread等函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天学习了TCP协议的知识,写了一个本机测试套接字收发的例子,用到了TCP编程和线程的一些函数,在vim下运行无误,代码如下:

客户端:

<p>#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
void *cil_recv(void *arg)</p>{
   int fd = (int)arg;
   char buff[100];
   int ret;
   while(1)
   {
   ret = read(fd,buff,100);
   write(1,buff,ret);
   }
}

int main()
{
   draw();
   int fd = socket(AF_INET,SOCK_STREAM,0);
   
   struct sockaddr_in servaddr;
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(7770);
   servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

   connect(fd,(struct sockaddr *)&servaddr,sizeof(servaddr));
   
   pthread_t tid;
   pthread_create(&tid,NULL,cil_recv,(void *)fd);
   char buff[100];
   int ret;
   while(1)
   {
      fgets(buff,100,stdin);
      write(fd,buff,strlen(buff));
      if(strncmp(buff,"quit",4)==0)
      {
         pthread_cancel(tid);
         break;
      }
   }
   close(fd);
   return 0;
}


服务端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<sys/socket.h>  //socket()
#include<netinet/in.h>  //inet_addr()
#include<arpa/inet.h>
#include<unistd.h>   //read() /write()
#include<pthread.h>
#include<errno.h>


void *ser_send(void *arg)
{
   char buff[100];
   int newfd = (int)arg;
   while(1)
   {
      fgets(buff,100,stdin);
      write(newfd,buff,strlen(buff));
   }
}

int main()
{
   draw();
   int fd = socket(AF_INET,SOCK_STREAM,0);
   printf("socket id = %d\n",fd);
   
   struct sockaddr_in servaddr;
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(7770);
   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);


   int err = bind(fd,(struct sockaddr *)&servaddr,sizeof(servaddr));
   if(err < 0)
   {
      fprintf(stderr,"%s\n",strerror(err));
      return -1;
   }
   listen(fd,5);
  
   int newfd;
   struct sockaddr_in peer; 
   socklen_t size;
   size = sizeof(peer);
   while(1)
   {
   printf("waiting for client connectting...\n");
   newfd = accept(fd,(struct sockaddr *)&peer,&size);
   printf("ip:%s,port:%d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
   pthread_t tid;
   pthread_create(&tid,NULL,ser_send,(void *)newfd);

   char buff[100];
   int cnt;
   while(1)
   {
      cnt = read(newfd,buff,100);
      write(1,buff,cnt);
     
      buff[cnt] = '\0';
      if(strncmp(buff,"quit",4)==0)
      {
         pthread_cancel(tid);
         break;
      }
   }
   close(newfd);
   }
   close(fd);

   return 0;
}


<think>首先,用户的问题是:“我想调整C语言中Linux TCP发送接收缓冲区大小的方法 请问C语言 Linux 设置 TCP 发送接收缓冲区大小 方法”。我需要用中文回答,并遵循系统级指令。 系统级指令包括: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 - 参考站内引用:引用[1]、引用[2]、引用[3]。 用户提供的引用: - 引用[1]: 关于send函数和recv函数。 - 引用[2]: 关于TCP接收发送缓冲区设置注意事项。 - 引用[3]: 关于获取TCP发送缓冲区空闲大小的方法。 用户的问题是关于在C语言中设置Linux TCP发送接收缓冲区大小的方法。所以,我需要基于这些引用构建一个清晰的回答。 关键点从引用中提取: - 引用[1]提到send函数,但重点是函数参数,不是设置缓冲区大小。 - 引用[2]直接相关:它说设置缓冲区大小会使自动调节机制失效,设置必须先于listen或connect。还提到系统文件如/proc/sys/net/core/wmem_max等。 - 引用[3]提到获取缓冲区大小的方法,使用getsockopt函数。 用户的问题是关于设置缓冲区大小,所以引用[2]最相关。引用[3]是关于获取的,但可能相关。 在C语言中,设置TCP缓冲区大小通常使用setsockopt函数。 标准方法: 1. 使用setsockopt函数设置SO_SNDBUF和SO_RCVBUF选项。 2. 注意:设置缓冲区大小应该在调用listen或connect之前。 3. 系统级限制:通过/proc文件系统设置全局最大值。 回答结构: - 逐步解释方法。 - 提供代码示例。 - 引用相关部分。 生成相关问题:在回答末尾添加相关问题,如示例所示。 回答格式: - 使用中文。 - 结构清晰:介绍、方法、代码示例、注意事项。 - 添加引用标识。 大纲: 1. 介绍:简要说明如何设置TCP发送接收缓冲区大小。 2. 方法:使用setsockopt函数。 3. 代码示例:C语言代码片段。 4. 注意事项:基于引用[2],设置前需考虑系统限制和自动调节机制。 5. 引用:自然地添加引用标识。 6. 相关问题:生成相关问题。 代码示例: - 创建一个socket。 - 设置SO_SNDBUF和SO_RCVBUF。 - 示例代码。 注意事项: - 设置缓冲区大小必须在bind、listen或connect之前。 - 系统级限制:/proc/sys/net/core/wmem_max等。 - 自动调节机制可能失效(引用[2])。 相关问题: 1. 如何获取当前的TCP发送接收缓冲区大小? 2. 设置缓冲区大小有什么最佳实践? 3. TCP缓冲区大小如何影响网络性能? 引用标识: - 在相关段落末尾添加[^1]、[^2]、[^3]。 确保LaTeX:如果涉及数学表达式,但这里可能不需要,除非有公式。用户问题不涉及数学,所以可能不需要LaTeX。但指令说所有行内数学表达式必须用$...$格式,所以如果有变量或数字,可以用$size$等,但可能不必要。 现在,构建回答。</think>### 设置 Linux TCP 发送接收缓冲区大小的方法 在 C 语言中调整 Linux TCP 发送接收缓冲区大小,主要通过 `setsockopt` 函数实现。这种方法允许你在程序运行时动态设置缓冲区大小,但需注意系统级限制和最佳实践。以下我将逐步解释方法,并提供代码示例。 #### 1. **核心方法:使用 `setsockopt` 函数** - `setsockopt` 是标准套接字 API 的一部分,用于设置套接字选项。 - 设置发送缓冲区大小:使用选项 `SO_SNDBUF`。 - 设置接收缓冲区大小:使用选项 `SO_RCVBUF`。 - 函数原型: ```c int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); ``` - `sockfd`: 套接字描述符(通过 `socket` 函数创建)。 - `level`: 设置为 `SOL_SOCKET`,表示操作套接字层。 - `optname`: 选项名(`SO_SNDBUF` 或 `SO_RCVBUF`)。 - `optval`: 指向缓冲区大小的指针(类型为 `int*`)。 - `optlen`: `optval` 的大小(通常为 `sizeof(int)`)。 - 返回值:成功时返回 0,失败时返回 -1 并设置 `errno`。 - **关键点**:设置缓冲区大小必须在调用 `listen`(服务器端)或 `connect`(客户端)之前进行,否则设置可能无效或导致未定义行为[^2]。 #### 2. **代码示例** 以下是一个完整的 C 语言示例,展示如何创建 TCP 套接字并设置发送接收缓冲区大小。假设我们要将发送缓冲区设置为 64KB,接收缓冲区设置为 128KB(注意:实际值受系统限制)。 ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建 TCP 套接字 if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 设置发送缓冲区大小(64KB) int send_buf_size = 65536; // 64 * 1024 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &send_buf_size, sizeof(send_buf_size)) < 0) { perror("setsockopt SO_SNDBUF failed"); close(sockfd); exit(EXIT_FAILURE); } // 设置接收缓冲区大小(128KB) int recv_buf_size = 131072; // 128 * 1024 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recv_buf_size, sizeof(recv_buf_size)) < 0) { perror("setsockopt SO_RCVBUF failed"); close(sockfd); exit(EXIT_FAILURE); } // 验证设置(可选,使用 getsockopt 检查实际值) int actual_send_size; socklen_t len = sizeof(actual_send_size); if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &actual_send_size, &len) < 0) { perror("getsockopt failed"); } else { printf("Actual send buffer size set: %d bytes\n", actual_send_size); } // 后续操作:bind, listen/connect 等(必须在 setsockopt 之后) // 示例:绑定到端口(此处省略具体实现) struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8080); addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind failed"); close(sockfd); exit(EXIT_FAILURE); } // 如果是服务器,调用 listen;如果是客户端,调用 connect // listen(sockfd, 5); 或 connect(sockfd, ...); close(sockfd); // 关闭套接字 return 0; } ``` #### 3. **注意事项** - **系统级限制**:`setsockopt` 设置的缓冲区大小不能超过系统全局最大值。这些值通过 `/proc` 文件系统定义: - 发送缓冲区最大大小:`/proc/sys/net/core/wmem_max` - 接收缓冲区最大大小:`/proc/sys/net/core/rmem_max` - 默认值:`/proc/sys/net/core/wmem_default` 和 `/proc/sys/net/core/rmem_default` 你可以通过 shell 命令修改这些值(例如 `echo 262144 > /proc/sys/net/core/wmem_max`),但需 root 权限。程序中的设置值若超过这些限制,会被内核自动截断到最大值[^2]。 - **自动调节机制**:Linux 内核默认使用 TCP 自动调节机制(如 BBR 或 CUBIC)来优化缓冲区大小。手动设置缓冲区会禁用此机制,可能导致性能下降。因此,仅在特定场景(如高延迟网络)下推荐手动设置[^2]。 - **错误处理**:总是检查 `setsockopt` 的返回值和 `errno`。常见错误包括: - `EINVAL`:无效参数(如缓冲区大小过大)。 - `ENOBUFS`:系统资源不足。 - **性能影响**:增大缓冲区可提升高吞吐量应用的性能(如视频流),但可能增加内存开销。建议通过测试(如使用 `iperf`)优化大小。 - **获取当前大小**:如果需要查询当前缓冲区大小,使用 `getsockopt` 函数(如代码示例中所示),这与引用[3]中描述的方法一致[^3]。 #### 4. **相关引用** - 设置缓冲区大小必须先于 `listen` 或 `connect` 调用,否则内核可能忽略设置[^2]。 - 在 TCP 协议中,发送缓冲区通过 `send` 函数操作,但缓冲区大小设置独立于发送逻辑[^1]。 通过以上方法,你可以灵活控制 TCP 缓冲行为。如果遇到系统限制,建议先检查 `/proc` 文件值并适当调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值