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


    1. 概述

    Socket编程中,使用send()传送数据时,返回结果受到以下几个因素的影响:
    • Blocking模式或non-blocking模式
    • 发送缓冲区的大小
    • 接收窗口大小
    本文档介绍通过实验的方式,得出(收发)缓冲区大小对send结果的影响。实验使用C语言。

    2 数据发送和接收的过程

    如下图所示,程序调用send()发送数据时,数据将首先进入发送缓冲区,等待发送。系统底层socket负责数据的传送,数据通过网络到达接收方的缓冲区。接收方缓冲区内的数据,等待应用程序调用recv()读取。


    3 实验一:Blocking模式下

    3.1 实验步骤

    发送端:blocking模式send()发送8192字节,使用setsockopt设置SO_SNDBUF改变发送缓冲区的大小。
    接收端:建立连接后进入睡眠。使用setsockopt设置SO_RCVBUF改变接收缓冲区的大小。

    3.2 实验得到的数据

     

     3.3实验结论

    “已发送字节 + 缓冲区中待发送字节 > 总字节”时,send()能立即返回,否则处于阻塞等待。

    4 实验二:Non-Blocking模式下

    4.1 实验步骤

    发送端:non-blocking模式send()发送8192字节,使用setsockopt设置SO_SNDBUF改变发送缓冲区的大小。
    接收端:建立连接后进入睡眠。使用setsockopt设置SO_RCVBUF改变接收缓冲区的大小。

    4.2 实验数据

     

    4.3 实验结论

    随着SNDBUF增大,send()返回已发送字节越大。接收窗口大小对结果影响不是线性的。实际已接收的只有窗口大小。

    5. 实验原代码

    5.1 服务器端代码

      1 #include <netinet/in.h>
      2 #include <sys/socket.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <stdint.h>
      6 #include <string.h>
      7 #include <errno.h>
      8 
      9 int
     10 init_server(int type, const struct sockaddr_in *addr)
     11 {
     12     int fd;
     13     int err = 0;
     14     int reuse = 1;
     15 
     16     if ((fd = socket(AF_INET, type, 0)) < 0) {
     17         printf("Failed to create socket.\n");
     18         exit(1);
     19     }
     20     if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
     21         printf("Server Bind Failed: %d\n", errno);
     22         exit(1);
     23     }
     24     if (listen(fd, 5) < 0) {
     25         printf("Fail to listen\n");
     26         exit(1);
     27     }
     28     return fd;
     29 }
     30 
     31 void
     32 serve(int fd, int n_to_send, int s_buf_size, int flag)
     33 {
     34     int clfd, clfd_2;
     35     struct sockaddr_in client_addr;
     36     char *buf;
     37     const char  *addr;
     38     socklen_t alen = sizeof(int);
     39     int n=0;
     40     int i;
     41     ssize_t num;
     42 
     43     /* initialize the send buffer */
     44     buf = malloc(n_to_send * sizeof(char));
     45     for (i = 0; i < n_to_send; i++)
     46         buf[i] = '=';
    47 
     48     /* change the send buffer size */
     49     getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&n, &alen);
     50     printf("SEND buffer size: %d\n", n);
     51     getsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, (char *)&n, &alen);
     52     printf("SEND LOWAT size: %d\n", n);
     53     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&s_buf_size, sizeof(int)) < 0) {
     54         printf("fail to change SNDbuf.\n");
     55         exit(2);
     56     }
     57     getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&n, &alen);
     58     printf("Current SEND buffer size: %d\n", n);
     59 
     60     /* loop: accept a client, and send buffer to it */
     61     while(1) {
     62         printf("waiting for clients...\n");
     63         clfd = accept(fd, (struct sockaddr*)&client_addr, &alen);
     64         if(clfd < 0) {
     65             printf("accept error.");
     66             exit(4);
     67         }
     68         printf("new client\n");
     69         printf("Sending %d bytes...\n", n_to_send);
     70         i = send(clfd, buf, n_to_send, flag);
     71         printf("send %d bytes.\n", i);
     72         close(clfd);
     73         printf("\n\n");
     74     }
     75 }
     76 
     77 int
     78 main(int argc, char *argv[])
     79 {
     80     char host[] = "127.0.0.1";
     81     struct sockaddr_in server_addr;
     82     uint32_t s_addr;
     83     int fd;
     84     int n_to_send, s_buf_size, flag;
     85 
     86     if (argc != 4) {
     87         printf("useage %s <num to send> <send buf size> <wait_flag:1|0>\n", argv[0]);
     88         exit(1);
     89     }
     90     n_to_send = atoi(argv[1]);
     91     s_buf_size = atoi(argv[2]);
    92     flag = atoi(argv[3]) ? 0 : MSG_DONTWAIT;
     93 
     94     bzero(&server_addr, sizeof(server_addr));
     95     inet_pton(AF_INET, host, &s_addr);
     96     server_addr.sin_family = AF_INET;
     97     server_addr.sin_addr.s_addr = s_addr;
     98     server_addr.sin_port = htons(9000);
     99 
    100     fd = init_server(SOCK_STREAM, &server_addr);
    101     serve(fd, n_to_send, s_buf_size, flag);
    102 
    103     exit(0);
    104 }

    5.2 客户端代码

      1 #include <netinet/in.h>
      2 #include <unistd.h>
      3 #include <errno.h>
      4 #include <sys/socket.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <stdint.h>
      9 
     10 #define SLEEP_TIME 120
     11 
     12 void
     13 tcp_client(int sockfd, struct sockaddr_in *s_addr, int r_buf_size)
     14 {
     15     int n, i;
     16     socklen_t slen = sizeof(int);
     17     int rcv_len;
     18 
     19     /* change receiving buffer size */
     20     getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcv_len, &slen);
     21     printf("Receive buffer size: %d\n", rcv_len);
     22     setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &r_buf_size, sizeof(int));
     23     getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcv_len, &slen);
     24     printf("Current Receive buffer size: %d\n", rcv_len);
     25 
     26     /* connect to server */
     27     if(connect(sockfd, (struct sockaddr*)s_addr, sizeof(*s_addr))) {
     28         printf("Can not connect to server.\n");
     29         exit(2);
     30     }
     31 
     32     sleep(SLEEP_TIME);
     33 }
     34 
     35 int
     36 main(int argc, char *argv[])
     37 {
     38     char server_ip[] = "127.0.0.1";
     39     int port = 9000;
     40     uint32_t s_addr;
     41     int s_fd;
     42     struct sockaddr_in server_addr;
     43     int r_buf_size;
     44 
     45     if (argc != 2) {
     46         printf("usage: %s <recv_buf_size>\n", argv[0]);
    47         exit(1);
     48     }
     49     r_buf_size = atoi(argv[1]);
     50 
     51     bzero(&server_addr, sizeof(server_addr));
     52     inet_pton(AF_INET, server_ip, &s_addr);
     53     server_addr.sin_family = AF_INET;
     54     server_addr.sin_addr.s_addr = s_addr;
     55     server_addr.sin_port = htons(port);
     56     if ((s_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     57         printf("Fail to create socket.");
     58         exit(1);
     59     }
     60 
     61     tcp_client(s_fd, &server_addr, r_buf_size);
     62     exit(0);
     63 }

  • 相关阅读:
    外媒评出的中国最美的地方
    外媒评出的中国最美的地方
    中国十大徒步路线,你走过几个?
    中国十大徒步路线,你走过几个?
    还在用Ghost?Windows 7时代用True Image了
    查看手机已经记住的WIFI密码
    查看手机已经记住的WIFI密码
    量子力学的经典教材
    量子力学的经典教材
    索尼全画幅微单A7/A7R上市
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3015617.html
Copyright © 2020-2023  润新知