当前位置:   article > 正文

UDP网络编程_udp编程

udp编程

一、UDP的概念

1.1、UDP——面向无连接(无连接,是因为UDP里有了对方的地址,直接发就好)

特点:

          1、邮件系统服务模式的抽象
          2、每个分组都携带完整的目的地址
          3、不能保证分组的先后顺序
          4、不进行分组出错的恢复和重传
          5、不保证数据传输的可靠性 

1.2、UDP协议

 面向无连接的用户数据报协议,在传输数据前不需要先建立连接;目地主机的运输层收到 UDP 报文后,不需要给出任何确认。

UDP 其它特点
                 1、相比 TCP 速度稍快些
                 2、简单的请求/应答应用程序可以使用 UDP
                 3、对于海量数据传输不应该使用 UDP
                 4、广播和多播应用必须使用 UDP

UDP 应用
                DNS(域名解析)、NFS(网络文件系统)、RTP(流媒体)等

二、网络编程接口socket

2.1、socket 作用

            提供不同主机上的进程之间的通信

2.2、socket 特点

1、socket 也称“套接字”
2、是一种文件描述符,代表了一个通信管道的一个端点
3、类似对文件的操作一样,可以使用 read、write、close 等函数对 socket 套接字进行网络  数据的收取和发送等操作。
4、得到 socket 套接字(描述符)的方法调用 socket()

三、UDP编程C/S架构

四、创建 socket 套接字

头文件:

             #include <sys/types.h>
             #include <sys/socket.h>

函数:

            int socket(int domain, int type, int protocol);
功能:

           创建一个套接字,返回一个文件描述符
参数:
            domain:通信域,协议族
                           AF_UNIX     本地通信
                           AF_INET     ipv4网络协议(常用)
                           AF_INET6   ipv6网络协议
                           AF_PACKET 底层接口

             type:套接字的类型 
                          SOCK_STREAM 流式套接字(TCP)
                          SOCK_DGRAM 数据报套接字(UDP)本章学习UDP
                          SOCK_RAW 原始套接字(用于链路层)
             protocol:附加协议,如果不需要,则设置为0
 返回值:
               成功:文件描述符
               失败:‐1

 特点:

           创建套接字时,系统不会分配端口
           创建的套接字默认属性是主动的,即主动发起服务的请求;当作为服务器时,往往需要修改为被动的。

五、创建UDP套接字

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <stdlib.h>
  5. int main(int argc, char const *argv[])
  6. {
  7. //使用socket函数创建套接字
  8. //创建一个用于UDP网络编程的套接字
  9. int sockfd;
  10. if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == ‐1)
  11. {
  12. perror("fail to socket");
  13. exit(1);
  14. }
  15. printf("sockfd = %d\n", sockfd);
  16. return 0;
  17. }

运行结果

sockfd = 3 

六、UDP编程——发送、绑定、接收数据

6.1、发送数据——sendto()函数

头文件

             #include <sys/types.h>
             #include <sys/socket.h>
函数:

            ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:

            发送数据
参数:
                sockfd:文件描述符,socket的返回值
                     buf:要发送的数据
                     len:buf的长度
                  flags:标志位
                               0 阻塞   (基本都设置为0)
                              MSG_DONTWAIT 非阻塞
           dest_addr:目的网络信息结构体(需要自己指定要给谁发送)
               addrlen:dest_addr的长度
返回值:
                   成功:发送的字节数
                   失败:‐1

此函数,重点 :const struct sockaddr *dest_addr   如何构建

通过man手册查询:sockaddr通用结构体

头文件:

                 #include <netinet/in.h>

函数结构体:
                      struct sockaddr
                   {
                       sa_family_t sa_family;   // 2字节
                       char sa_data[14]           //14字节
                    };

 但是,在网络编程中经常使用的结构体sockaddr_in

6.2、sockaddr_in(重点)

头文件:

                #include <netinet/in.h>

 函数结构体:

 
 struct sockaddr_in
    {
        sa_family_t sin_family;            //协议族 2字节
        in_port_t sin_port;                    //端口号 2字节
        struct in_addr sin_addr;       //ip地址 4字节
        char sin_zero[8]                       //填充,不起什么作用 8字节
          };

   struct in_addr
      {
      in_addr_t s_addr;                       //ip地址 4字节
             };

 6.2.1、sockaddr_in使用说明

           在定义源地址和目的地址结构的时候,选用struct sockaddr_in;
  例:
           struct sockaddr_in my_addr;
          当调用编程接口函数,且该函数需要传入地址结构时需要用struct sockaddr进行强制转换
例:
         bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr));

七、向"网络调试助手"发送消息(作为服务器)

        设置网络调试助手(在windows下运行的软件)中的属性


注意:ip地址不能随意设置,必须是当前windows的ip地址

 八、unbantu下客户端发送给windows下运行"网络调试助手"

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <unistd.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include<string.h>
  9. #define N 128
  10. int main(int argc, char **argv)
  11. {
  12. if(argc<3)
  13. {
  14. fprintf(stderr,"%s ip post",argv[0]);
  15. exit(1);
  16. }
  17. int sockfd;
  18. if((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1)
  19. {
  20. perror("fail to sockfd");
  21. exit(1);
  22. }
  23. printf("sockfd = %d \n",sockfd);
  24. struct sockaddr_in myaddr;
  25. myaddr.sin_family=AF_INET;
  26. myaddr.sin_port =htons(atoi(argv[2]));
  27. myaddr.sin_addr.s_addr = inet_addr(argv[1]);
  28. socklen_t addrlen=sizeof(myaddr);
  29. char buf[N]="";
  30. while(1)
  31. {
  32. fgets(buf,N,stdin);
  33. // buf[strlen(buf)-1]='\0'; //有这句话,不会换行
  34. if(sendto(sockfd,buf,N,0,(struct sockaddr*)&myaddr,addrlen)==-1)
  35. {
  36. perror("sendto fail");
  37. exit(1);
  38. }
  39. }
  40. close(sockfd);
  41. return 0;
  42. }

运行结果

 

九、unbantu作为服务器接收数据,网络调试助手作为客户端发送数据 

 9.1、服务器为客户端服务,因此需要有固定的ip和端口号——bind函数绑定

头文件:

            #include <sys/types.h>
            #include <sys/socket.h>
函数:

          int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:

          将套接字与网络信息结构体绑定
参数:
           sockfd:文件描述符,socket的返回值
              addr:网络信息结构体
    struct sockaddr:通用结构体(一般不用
            使用网络信息结构体 sockaddr_in

结构体头文件

               #include <netinet/in.h>
 结构体函数

               struct sockaddr_in
               addrlen:addr的长度
 返回值:
               成功:0
               失败:‐1

 9.2、sockaddr_in使用说明

头文件:

                #include <netinet/in.h>

 函数结构体:

 
 struct sockaddr_in
    {
        sa_family_t sin_family;            //协议族 2字节
        in_port_t sin_port;                    //端口号 2字节
        struct in_addr sin_addr;       //ip地址 4字节
        char sin_zero[8]                       //填充,不起什么作用 8字节
          };

   struct in_addr
      {
      in_addr_t s_addr;                       //ip地址 4字节
             };

 9.3、bind的绑定示例

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. int main(int argc , char **argv[])
  8. {
  9. int sockfd;
  10. if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
  11. {
  12. perror("fail to sockfd");
  13. exit(1);
  14. }
  15. printf("sockfd= %d\n",sockfd);
  16. //bind的函数
  17. struct sockaddr_in mysockaddr;
  18. mysockaddr.sin_family=AF_INET;
  19. mysockaddr.sin_port =htons(8080);
  20. mysockaddr.sin_addr.s_addr = inet_addr("10.152.203.29");
  21. socklen_t addrlen = sizeof(mysockaddr);
  22. if(bind(sockfd,(struct sockaddr *)&mysockaddr,addrlen)==-1)
  23. {
  24. perror("fail to bind");
  25. exit(1);
  26. }
  27. }

补充知识:

                 inet_addr

头文件:

              #include <sys/socket.h>
              #include <netinet/in.h>
              #include <arpa/inet.h>
函数:
             in_addr_t    inet_addr(const char *cp);
 功能:

             将点分十进制ip地址转化为整形数据

              此转换的整形数据也是网络字节序
 参数:
              cp:点分十进制的IP地址
 返回值:
              成功:整形数据
 

 atoi函数(字符串转化成整数)

 头文件

                  #include<stdlib.h>
函数

               int atoi(const char *nptr);
功能
              把字符串转化为int类型
返回

             返回转换后的整型数。

端口号,在我们输入时候,是以字符串形式表达,而我们的结构sockaddr_in 接收的是 整形

因此需要:  atoi(端口号)     变为整形数。 

只是转为整形数,还不行,由于不同计算机之间通讯,需要转换自己的字节序为网络字节序

因此需要: htons(atoi(端口号));

十、接收到数据——recvfrom函数 

头文件

                  #include <sys/types.h>
                  #include <sys/socket.h>
函数
         ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,5 struct sockaddr *src_addr, socklen_t *addrlen);
功能:

            接收数据
参数:

               sockfd:文件描述符,socket的返回值
                    buf:保存接收的数据
                    len:buf的长度
                 flags:标志位
                                        0 阻塞(基本都设置0)
                                        MSG_DONTWAIT 非阻塞
                 src_addr:源的网络信息结构体(自动填充,定义变量传参即可

                 会自动接收对方的ip地址,和端口号,存放此结构体中
                 addrlen:src_addr的长度
 返回值:
               成功:接收的字节数
                失败:‐1

 10.1、recvfrom函数示例

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #define N 128
  11. int main()
  12. {
  13. char buf[N]="";
  14. struct sockaddr_in recvfrom_addr;
  15. socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
  16. while(1)
  17. {
  18. if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
  19. {
  20. perror("fail to recvfrom");
  21. exit(1);
  22. }
  23. printf("%s\n",buf);
  24. }
  25. return 0;
  26. }

十一、unbantu作为服务端 (代码示例)

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #define N 128
  11. int main(int argc , char *argv[])
  12. {
  13. if(argc<3)
  14. {
  15. fprintf(stderr, "%s ip port ",argv[0]);
  16. exit(1);
  17. }
  18. int sockfd;
  19. if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
  20. {
  21. perror("fail to sockfd");
  22. exit(1);
  23. }
  24. printf("sockfd= %d\n",sockfd);
  25. struct sockaddr_in mysockaddr;
  26. mysockaddr.sin_family=AF_INET;
  27. mysockaddr.sin_port =htons(atoi(argv[2]));
  28. mysockaddr.sin_addr.s_addr = inet_addr(argv[1]);
  29. socklen_t addrlen = sizeof(mysockaddr);
  30. if(bind(sockfd,(struct sockaddr*)&mysockaddr,addrlen)<0)
  31. {
  32. perror("fail to bind");
  33. exit(1);
  34. }
  35. char buf[N]="";
  36. struct sockaddr_in recvfrom_addr;
  37. socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
  38. while(1)
  39. {
  40. if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
  41. {
  42. perror("fail to recvfrom");
  43. exit(1);
  44. }
  45. printf("%s\n",buf);
  46. }
  47. return 0;
  48. }

 运行结果

 注意:当我们关掉unbantu服务端程序时,如果在运行同一个端口号,会遇到运行错误。需要换一个端口号才可以运行成功。

当我们发送信息时,先把发送的内容写进buf里,然后再传输给对方。当我们再继续发信息时,原先buf里面装的内容不会清除,如果发的信息多,能覆盖之前buf内容,则输出正常。如果发的信息少,不能覆盖原先的buf的内容,只覆盖前面几个数据,后面原先的数据,照常发送给对方。

十二、客户端发信息并能接收服务端回信息(更完善) 

12.1、客户端示例代码

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <unistd.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include<string.h>
  9. #define N 128
  10. int main(int argc, char **argv)
  11. {
  12. if(argc<3)
  13. {
  14. fprintf(stderr,"%s ip post",argv[0]);
  15. exit(1);
  16. }
  17. int sockfd;
  18. if((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1)
  19. {
  20. perror("fail to sockfd");
  21. exit(1);
  22. }
  23. printf("sockfd = %d \n",sockfd);
  24. struct sockaddr_in myaddr;
  25. myaddr.sin_family=AF_INET;
  26. myaddr.sin_port =htons(atoi(argv[2]));
  27. myaddr.sin_addr.s_addr = inet_addr(argv[1]);
  28. socklen_t addrlen=sizeof(myaddr);
  29. char buf[N]="";
  30. while(1)
  31. {
  32. char context[50]="";
  33. fgets(buf,N,stdin);
  34. // buf[strlen(buf)-1]='\0';
  35. if(sendto(sockfd,buf,N,0,(struct sockaddr*)&myaddr,addrlen)==-1)
  36. {
  37. perror("sendto fail");
  38. exit(1);
  39. }
  40. if(recvfrom(sockfd,context,sizeof(context),0,(struct sockaddr*)&myaddr,&addrlen)==-1)
  41. {
  42. perror("fail to recvfrom");
  43. exit(1);
  44. }
  45. printf("from server: %s\n", context);
  46. }
  47. close(sockfd);
  48. return 0;
  49. }

12.2、服务端示例代码

  1. #include<stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include<stdlib.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include<string.h>
  11. #define N 128
  12. int main(int argc , char *argv[])
  13. {
  14. if(argc<3)
  15. {
  16. fprintf(stderr, "%s ip port ",argv[0]);
  17. exit(1);
  18. }
  19. int sockfd;
  20. if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
  21. {
  22. perror("fail to sockfd");
  23. exit(1);
  24. }
  25. printf("sockfd= %d\n",sockfd);
  26. struct sockaddr_in mysockaddr;
  27. mysockaddr.sin_family=AF_INET;
  28. mysockaddr.sin_port =htons(atoi(argv[2]));
  29. mysockaddr.sin_addr.s_addr = inet_addr(argv[1]);
  30. socklen_t addrlen = sizeof(mysockaddr);
  31. if(bind(sockfd,(struct sockaddr*)&mysockaddr,addrlen)<0)
  32. {
  33. perror("fail to bind");
  34. exit(1);
  35. }
  36. char buf[N]="";
  37. struct sockaddr_in recvfrom_addr;
  38. socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
  39. while(1)
  40. {
  41. char text[50]="";
  42. if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
  43. {
  44. perror("fail to recvfrom");
  45. exit(1);
  46. }
  47. printf("ip:%s ,port:%d\n", inet_ntoa(recvfrom_addr.sin_addr), ntohs(recvfrom_addr.sin_port));
  48. printf("%s\n",buf);
  49. strcat(text, " *_*");
  50. if(sendto(sockfd, text, sizeof(text), 0, (struct sockaddr *)&recvfrom_addr, addrlen) < 0)
  51. {
  52. perror("fail to sendto");
  53. exit(1);
  54. }
  55. }
  56. close(sockfd);
  57. return 0;
  58. }

 运行结果

可以实现多并发 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/84453
推荐阅读
相关标签
  

闽ICP备14008679号