• 28UDP


    UDP通信流程步骤:

    服务端: 等待(被动)接收发送

    1: 创建 socket:  socket()

    2: 绑定端口:      bind()

    3: 读取消息:      read()

    4: 发送消息:      write()

    5: 关闭套接字:  close()

    客户端:主动发送接收

    1: 创建 socket:   socket()

    2: 发送数据:        write()

    3: 接受结果:         read()

    4: 关闭套接字:     close()

    UDP通信流程图:

    UDP通信

    1.没有固定连接

    2.客户端发完包,就不管了,也不知道服务端是不是收到了

    UDP创建套接字、绑定套接字的方式与TCP一样,可参考TCP。

    发送消息

    sendto(int sockfd, void* buf,  size_t len,  int flags,

              struct sockaddr *to,  socklen_t tolen);

    sockaddr由sockaddr_in转换。

    UDP 没有accept创建新的通信fd,需要指定目标地址

    函数可以用于TCP通信,后面两个参数会忽略

    接收消息

    recvfrom(int sockfd, void *buf,  size_t len ,  int flags,

                 sturct sockaddr *from,  socklen_t *fromlen)

    UDP 没有 accept 函数来获取对端地址,这里增加了2个参数

    函数可以用于TCP通信

    例子:

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    #include<sys/socket.h>

    #include<netinet/in.h>

    #include<arpa/inet.h>

    #include<unistd.h>

    #define SRV_PORT  8888

    #define CLT_PORT  6666

    void Udp_server()

    {

          int fd;

          int iRet;

          struct sockaddr_in addr;

          socklen_t addrlen = sizeof(addr);

          //创建套接字

          fd = socket(PF_INET, SOCK_DGRAM, 0);

          if (fd < 0)

          {

               perror("Fail to socket!");

               return;

          }

          addr.sin_family = AF_INET;

          addr.sin_port = htons(SRV_PORT);

          addr.sin_addr.s_addr = htonl(INADDR_ANY);

          //绑定,可以让客户端知道通过什么IP地址和端口号来连接

          iRet = bind(fd, (struct sockaddr*)&addr, addrlen);

          if (iRet)

          {

               perror("Fail to bind!");

               close(fd);

               return;

          }

         

          struct sockaddr_in srcaddr;

          char szBuf[1000];

          char szMsg[] = "[UDP]I Received!";

          while(1)

          {

               //接收,并获取客户端的IP和端口号(struct sockaddr*)&srcaddr

               memset(szBuf, 0, 1000);

               iRet = recvfrom(fd, szBuf, 1000, 0, (struct sockaddr*)&srcaddr, &addrlen);

               if (iRet < 0)

               {

                     perror("Fail to recvfrom!");

                     break;

               }

              

               printf("Recv:%s ", szBuf);  

         

               //发送

               fprintf(stderr,"Echo:");

               scanf("%s",szMsg);

               sendto(fd, szMsg, strlen(szMsg), 0, (struct sockaddr*)&srcaddr, addrlen);

          }

          close(fd);

          return;

    }

    void Udp_client()

    {

          int fd;

          int iRet;

          struct sockaddr_in addr;

          socklen_t  addrlen = sizeof(addr);

          fd = socket(PF_INET, SOCK_DGRAM, 0);

          if (fd < 0)

          {

               perror("Fail to socket!");

               return;

          }

          /*

          addr.sin_family = AF_INET;

          addr.sin_port = htons(CLT_PORT);

          addr.sin_addr.s_addr = htonl(INADDR_ANY);

          iRet = bind(fd, (struct sockaddr*)&addr, addrlen);

          if (iRet)

          {

               perror("Fail to bind!");

               close(fd);

               return;

          }

          */

          struct sockaddr_in srvaddr;

          char szIp[16] = ;

          int  port;

          fprintf(stderr, "Input server IP and port:");

          scanf("%s%d", szIp, &port);

         

          srvaddr.sin_family = AF_INET;

          srvaddr.sin_port = htons((short)port);

          srvaddr.sin_addr.s_addr = inet_addr(szIp);

          char szBuf[100];

          char szRcv[1000];

          while(1)

          {

               memset(szBuf, 0, 100);

               fprintf(stderr, "->");

               read(STDIN_FILENO, szBuf, 100);

              

               sendto(fd, szBuf, strlen(szBuf), 0, (struct sockaddr*)&srvaddr, addrlen);

              

               memset(szRcv, 0, 1000);

               iRet = recvfrom(fd, szRcv, 1000, 0, (struct sockaddr*)&srvaddr, &addrlen);

               if (iRet < 0)

               {

                     perror("Fail to recvfrom!");

                     break;

               }

               printf("Recv:%s ", szRcv);

          }

          close(fd);

          return;

              

    }

    int main(int argc, char** argv)

    {

          if (argc!=2

             || (strcmp(argv[1], "s") && strcmp(argv[1], "c"))

               )

          {

               printf("Usage: %s [ c | s ] ", argv[0]);  

               printf(" s: For start udp server ");

               printf(" c: For start udp client ");

               return 0;

          }

          if (argv[1][0] == 's')

          {

               Udp_server();

          }

          else if (argv[1][0] == 'c')

          {

               Udp_client();

          }

          return 0;

    }

    UDP打洞:

    打洞就是让对方不需要通过服务器的转换,直接使用公网IP地址进行通信。

    解析:

    一般的主机都是使用私有IP地址(在不同的局域网中私有IP地址可以重复的),对方主机通过路由路转换成公有IP地址,再进行通信。

    打洞,当主机A向某一服务器发送数据时,此时在服务器上,显示的是主机A的公网IP地址和端口号,要做的就是将该IP地址和端口号再一次返回给主机A。那么主机A就知道了自己的公网IP和端口号。此时主机B就可以直接对主机A发送数据,进而可以相互通信。

  • 相关阅读:
    MySQL 安装和配置
    其它 Google Chrome 已停止工作
    VUE 父组件和子组件相互传值 组件之间的数据传递
    SpringBlade 源码 个性化修改 添加字典时 自动填充字典值
    MyBatis-Plus SpringBlade 生成代码时 啥内容都没有 只有目录
    Oracle IIS部署报错
    pycharm连接sqlite后打开db文件不显示表的问题
    Hbase集群搭建以及启动(单点启动,群起)
    Flume的put和take事务
    稀疏数组学习
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/9216040.html
Copyright © 2020-2023  润新知