• UDP网络编程


    补充知识,TCP--send/recv函数

    1、网络发送数据:send() / wirte()

    功能:

    客户和服务器都用send函数来向另一端发送数据。客户端一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户端发送应答。

    1  #include <sys/types.h>
    2  #include <sys/socket.h>
    3 
    4  ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    5 //参数
    6 //sockfd:发送端的套接字描述符
    7 //buf     :存放所要发送的数据的缓冲区
    8 //len     :实际要发送的数据的字节数
    9 //flags   :一般设为0

    对比write()

    1 #include <unistd.h>
    2 
    3 ssize_t write(int fd, const void *buf, size_t count);
    4 
    5 //send比write函数多一个参数flags,其他相同
    6 //flags为0时,与write相同

    flags参数:

     1 0
     2 //当发送数据时,若发送的内核缓冲区满,且数据没有发送出去,就发生阻塞;
     3 
     4 MSG_DONTWAIT
     5 //非阻塞方式
     6 
     7 MSG_OOB
     8 //Sends out-of-band data on sockets that support this notion (e.g., //of type SOCK_STREAM);
     9 //the  underlying  protocol  must  also support out-of-band data.
    10 //用于发送TCP类型的带外数据

    2、网络接收数据:recv() / read()

    功能:

    从另一端接收数据

    1 #include <sys/types.h>
    2 #include <sys/socket.h>
    3 
    4 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    5 //参数:
    6 //接收端的套接字描述符
    7 //存放recv接收到的数据
    8 //buf长度
    9 //一般设为0

    对比read

    1 #include <unistd.h>
    2 
    3 ssize_t read(int fd, void *buf, size_t count);

    flags参数

     1 0
     2 //一般为0,阻塞操作
     3 MSG_DONTWAIT
     4 //非阻塞操作
     5 MSG_OOB
     6 //用于发送TCP类型的带外数据
     7 MSG_PEEK
     8 //
     9 //
    10 //
    MSG_PEEK标志可以用来读取套接字接收队列中可读的数据,一些情况会用到它,比如为了避免不阻塞而先检查套接字接收队列中可读的数据长度,再采取相应操作。
    当然,不阻塞也可采取其他的方法,例如非阻塞式I/O。
    
    MSG_PEEK标志会将套接字接收队列中的可读的数据拷贝到缓冲区,但不会使套接子接收队列中的数据减少,常见的是:例如调用recv或read后,导致套接字接收队列中的数据被读取后而减少,而指定了MSG_PEEK标志,可通过返回值获得可读数据长度,并且不会减少套接字接收缓冲区中的数据,所以可以供程序的其他部分继续读取。
    MSG_PEEK

     内核从网络接收数据并填充缓冲区,填充了200字节数据,读走了100字节后,后续的数据会向前移动,下次读取数据就又从头开始了,即TCP是以字符流方式读取的,没有边界。有时有些协议数据是完整的,有头有尾

    将flags设置为MSG_PEEK,第一次读取数据后,不会将buf读走的数据移除,再次调用读函数就可以读到刚才读到的数据。

    TCP与UDP的区别

    TCP传输时建立可靠的连接,而UDP是面向无连接的协议。使用UDP协议时,不需要建立连接,只需知道对方的IP地址和端口号,就可以直接发数据包。但是可能会丢包。

    虽然UDP传输数据不可靠,但是相对于TCP,其传输速度快,所需系统资源少。对于不要求可靠到达的数据可以用UDP协议。

    recv,write,send,read,recvfrom,sendto区别,详解

     sendto与recvfrom---UDP网络编程

    sendto

     1 #include <sys/types.h>
     2 #include <sys/socket.h>
     3 
     4 ssize_t send   (int sockfd, const void *buf, size_t len, int flags);
     5 
     6 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
     7                       const struct sockaddr *dest_addr, socklen_t addrlen);
     8 //该函数比send()多了两参数,
     9 //to表示目地机的IP地址和端口号信息,
    10 //而tolen常常被赋值为sizeof(struct sockaddr)。
    11 //Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。  

    recvfrom

     1 #include <sys/types.h>
     2 #include <sys/socket.h>
     3 
     4 ssize_t recv      (int sockfd, void *buf, size_t len, int flags);
     5 
     6 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
     7                         struct sockaddr *src_addr, socklen_t *addrlen);
     8 
     9 //from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。
    10 //fromlen常置为sizeof(struct sockaddr)。当recvfrom返回时,fromlen包含实际存入from中的数据字节数。
    11 //recvfrom()函数返回接收到的字节数或当出现错误时返回-1,并置相应的errno。

     测试代码:

     1 #include "net.h"
     2 
     3 int main(void)
     4 {
     5     int fd = -1;
     6     struct sockaddr_in sin; //网络环境下套接字的地址形式,对其进行操作
     7 
     8     /*1.创建套接字描述符fd*/
     9     if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)  //udp套接字
    10     {
    11         perror("socket");
    12         exit(1);
    13     }
    14     
    15     /*优化1:允许绑定地址快速重用*/
    16     int b_reuse = 1;
    17     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
    18 
    19     /*2.绑定*/
    20     /*2.1 填充struct sockaddr_in结构体变量*/
    21     bzero(&sin, sizeof(sin)); //初始值置零
    22     sin.sin_family = AF_INET;  //协议,ipv4
    23     sin.sin_port   = htons(SERV_PORT); //将端口号转为NBD
    24 
    25     /*优化2:让服务器能绑定在任意IP上*/
    26     sin.sin_addr.s_addr = htonl(INADDR_ANY);
    27     if(inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr)!=1)
    28     {
    29         perror("inet_pton");
    30         exit(1);
    31     }
    32     /*2.2绑定*/
    33     if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    34     {
    35         perror("bind");
    36         exit(1);
    37     }
    38 
    39     /*TCP--SOCK_STREAM是面向连接的,每次收发数据前必须通过connect
    40      * 建立双向连接确定任一方都可以收发数据 */
    41     /*UDP--SOCK_DGRAM无连接不可靠,通讯双方不知道对方是否收到数据
    42      * 任一方建立socket后就可以用recvfrom与sendto收发数据
    43      */
    44     /*使用recvfrom方法返回数据和客户端的地址与端口
    45      * 这样,服务器收到数据后,可直接调用sendto把数据发送给客户端*/
    46     
    47     char buf[BUFSIZ];
    48     struct sockaddr_in cin; //让系统填充发送方的信息
    49     socklen_t addrlen = sizeof(cin);
    50     printf("
    UDP server started!
    ");
    51     while(1)
    52     {
    53         bzero(buf,BUFSIZ);
    54         if(recvfrom(fd, buf, BUFSIZ-1, 0, (struct sockaddr *)&cin, &addrlen) < 0)
    55         {
    56             perror("recvfrom");
    57             continue;
    58         }
    59         
    60         //将发送方的HBD信息转为NBD
    61         char ipv4_addr[16];
    62         if(!inet_ntop(AF_INET, (void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
    63         {
    64             perror("inet_ntop");
    65             exit(1);
    66         }
    67         printf("Receive from(%s,%d),data:%s",ipv4_addr,ntohs(sin.sin_port),buf);
    68         
    69         //输入exit,退出
    70         if(!strncasecmp(buf,QUIT_STR, strlen(QUIT_STR)))
    71         {
    72             printf("client(%s,%d) is exiting!
    ",ipv4_addr,ntohs(sin.sin_port));
    73         }
    74     }
    75 
    76     close(fd);
    77     return 0;
    78 }
    server.c
     1 /*./client serv_ip serv_port 启动输入参数 */
     2 #include "net.h"
     3 void usage(char *s)
     4 {
     5     printf("
    This is udp demo!
    ");
     6     printf("
    Usage:
    	 %s serv_ip serv_port",s);
     7     printf("
    	 serv_ip: udp server ip address!");
     8     printf("
    	 serv_port: udp serv_port
    
    ");
     9 }
    10 
    11 int main(int argc, char *argv[])
    12 {
    13     int fd = -1;
    14 
    15     int port = SERV_PORT;
    16     port = atoi(argv[2]);
    17     if(port < 0 || (port > 0 && port <= 5000))
    18     {
    19         usage(argv[0]);
    20         exit(1);
    21     }
    22 
    23     struct sockaddr_in sin;
    24     //输入参数提示
    25     if(argc != 3)
    26     {
    27         usage(argv[0]);
    28         exit(1);
    29     }
    30     /*1.创建socket fd */
    31     if((fd = socket(AF_INET, SOCK_DGRAM, 0))<0)
    32     {
    33         perror("socket");
    34         exit(1);
    35     }
    36 
    37     /* */
    38     /*2.1 填充struct sockaddr_in结构体变量*/
    39     bzero(&sin, sizeof(sin)); //初始值置零
    40     sin.sin_family = AF_INET; //
    41     sin.sin_port = htons(SERV_PORT); //转化为NBD
    42 
    43     if(inet_pton(AF_INET, argv[1],(void *)&sin.sin_addr.s_addr) != 1)
    44     {
    45         perror("inet_pton");
    46         exit(1);
    47     }
    48 
    49     printf("UDP client starting...ok!
    ");
    50     char buf[BUFSIZ];
    51     while(1)
    52     {
    53         printf("Please input the string to server:");
    54         bzero(buf, BUFSIZ);
    55         if(fgets(buf, BUFSIZ-1, stdin) == NULL)
    56         {
    57             perror("fgets");
    58             continue;
    59         }
    60         /*获取到数据后就可以调用sendto函数了 */
    61         sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&sin, sizeof(sin));
    62          if(!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)))
    63         {
    64             printf("Clinet is exiting!
    ");
    65             break;
    66         }    
    67 
    68     }
    69     close(fd);
    70     return 0;
    71 }
    client.c

    测试结果:

    参考文章:

    TCP和UDP的最完整的区别

    UDP编程

    1

  • 相关阅读:
    权值线段树模版
    P2679 [NOIP2015 提高组] 子串
    P3747 [六省联考 2017] 相逢是问候
    P2822 [NOIP2016 提高组] 组合数问题
    P2331 [SCOI2005]最大子矩阵
    P1854 花店橱窗布置
    P5888 传球游戏
    Hard | LeetCode 42. 接雨水 | 单调栈 | 双指针
    Medium | LeetCode 621. 任务调度器 | 设计
    Medium | LeetCode 166. 分数到小数 | 数学
  • 原文地址:https://www.cnblogs.com/y4247464/p/12219104.html
Copyright © 2020-2023  润新知