socket---UDP通信

16 篇文章 0 订阅
12 篇文章 0 订阅

通信流程:
Server:
1.创建套接字 — 在内核中创建一个socket结构体
2.为套接字绑定地址信息
在创建套接字创建的socket结构体中加入IP+PORT信息
1.告诉操作系统主机收到的哪些数据应该交给当前的这个socket
2.确定发送数据的源端地址信息
3.接收数据
当前进程从指定的socket接收缓冲区中取出数据
4.发送数据
将要发送的数据放到socket发送缓存区中,内核选择合适时候封装发送
5.关闭套接字
Client:
1.创建套接字
2.为套接字绑定地址信息 (大多数情况下会忽略第二步,在发送数据时,若socket没有绑定地址,则系统会选择合适的地址进行绑定)
3. 发送数据
4. 接收数据
5.关闭套接字

udp_srv.c

 #include<stdio.h>
 #include<unistd.h>
 #include<string.h>
 #include<arpa/inet.h>  //字节序转换接口头文件
 #include<netinet/in.h> //地址结构头,协议类型文件
 #include<sys/socket.h> //套接字头文件
 
 int main(int argc,char *argv[])
 {
     //1.创建套接字---在内核中创建一个socket结构体
     //int socket(地址类型,套接字类型,协议类型)
     int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
     if(sockfd<0){
         perror("socket error\n");
         return -1;
     }
 
     //2.为套接字绑定地址信息
     //int bind(操作句柄,当前地址信息,地址信息长度)
     struct sockaddr_in addr; //定义IPv4d的地址结构
     addr.sin_family=AF_INET;  //定义地址类型为IPv4
     addr.sin_port=htons(9000);  //设置地址端口
     addr.sin_addr.s_addr=inet_addr("172.18.0.4 ");   //将点分10进制主机字节序转换为网络字节序                                                                        
     int len=sizeof(addr);
     int ret=bind(sockfd,(struct sockaddr*)&addr,len);
     if(ret<0){
         perror("bind error\n");
         return -1;
     }
 
     while(1){
         //3.接收数据
         //recvfrom(操作句柄,空间地址,数据长度,标志,对端地址,对端地址长度)
         char buf[1024] = {0};
         struct sockaddr_in paddr;  //定义对端地址信息结构体
         int len = sizeof(struct sockaddr_in);
         ret = recvfrom(sockfd, buf, 1023, 0, 
                 (struct sockaddr*)&paddr, &len);
         if (ret < 0) {
             perror("recvfrom error");
             return -1;
         }
         uint16_t cport = ntohs(paddr.sin_port);
         char *cip = inet_ntoa(paddr.sin_addr);
         printf("client-[%s:%d] say: %s\n", cip, cport, buf);
         
         //4. 回复数据
         memset(buf, 0x00, 1024);//初始化内存空间
         printf("server say: ");
         fflush(stdout);
         fgets(buf, 1023, stdin);
         //ssize_t sendto()
          ret = sendto(sockfd, buf, strlen(buf), 0,
                 (struct sockaddr*)&paddr, len);
         if (ret < 0 ) {
             perror("sendto error");
             return -1;
         }
     }
     //5.关闭套接字
     close(sockfd);
     return 0;
 }                         

updsocket.hpp

/*                                                                                                                                                                   
 * 封装实现一个udpsocket类
 * 通过实例化的对象调用对应的成员接口
 * 可以实现udp客户端或服务端的搭建
 */
#include<cstdio>
#include<iostream>
#include<string>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>

class UdpSocket{
   private:
       int _sockfd;   //套接字描述符
   public:
       //构造函数
       UdpSocket()
           :_sockfd(-1){}
       //1.创建套接字
       bool Socket(){
           //int socket(地址域类型,套接字类型,通信协议)
           _sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建socket
           if(_sockfd<0){
              perror("socket error");
              return false;
           }
           return true;
       }

       //2.为套接字绑定地址信息
       bool Bind(std::string &ip,uint16_t port){
         struct sockaddr_in addr; //定义地址信息结构体
         addr.sin_family=AF_INET;   //地址域类型IPv4
         addr.sin_port=htons(port);  //主机字节序端口号转换为网络字节序端口号
         addr.sin_addr.s_addr=inet_addr(ip.c_str()); //将字符串点分十进制IP地址转换为整型网络字节序IP地址
         socklen_t len=sizeof(struct sockaddr_in);
         int ret;
         //int bind(套接字操作句柄,地址信息,地址信息长度)
         ret=bind(_sockfd,(struct sockaddr*)&addr,len);
         if(ret<0){
            perror("bind error");
            return false;
         }
         return true;
       }
        
       //3.接收数据
       bool Recv(std::string *buf,std::string *ip=NULL,int *port=NULL){
            struct sockaddr_in addr;                                                                                                                                 
            socklen_t len=sizeof(struct sockaddr_in);
            char tmp[4096]={0};
            //recvfrom(操作句柄,发送空间首地址,发送数据长度,标识符,对端地址信息,地址结构长度)
            int ret=recvfrom(_sockfd,tmp,4096,0,(sockaddr*)&addr,&len);
            if(ret<0){
              perror("recvfrom error");
              return false;
            }
            buf->assign(tmp,ret); //自带申请空间拷贝数据
            if(ip!=NULL){
              *ip=inet_ntoa(addr.sin_addr);//将网络字节序IP地址转换为字节串点分十进制IP地址
            }
            if(port!=NULL){
              *port=ntohs(addr.sin_port);  //将网络端口号转换为主机端口号
            }
            return true;
       }

       //4.发送数据
       bool Send(std::string &data,const std::string &ip,const int port){
           struct sockaddr_in addr;
           addr.sin_family=AF_INET; //地址域类型为IPv4
           addr.sin_port=htons(port);  //主机端口号转换为网络端口号
           addr.sin_addr.s_addr=inet_addr(ip.c_str());  //将网络字节序IP地址转换为字节序串点分十进制IP地址
           socklen_t len=sizeof(struct sockaddr_in);
           //ssize_t snedto(操作句柄,空间首地址,发送数据长度,标识符,对端地址信息,地址结构长度)
           int ret=sendto(_sockfd,data.c_str(),data.size(),0,(sockaddr*)&addr,len);
           if(ret<0){
              perror("sendto error");
              return false;
           }
           return true;
       }
       //5.关闭套接字
       bool Close(){
          if(_sockfd!=-1){
            close(_sockfd);
          }
          return true;
       }
};                            

udp_cli.cpp

 #include"udpsocket.hpp"
 
 #define CHECK_RET(q)  if((q)==false){return -1;}
 int main(){
 
   UdpSocket sock;
   //1.创建套接字
   CHECK_RET(sock.Socket());
   //2.绑定地址信息(不推荐)
   while(1){
     //3.发送数据
       std::cout<<"client say: ";
       std::string buf;
       std::cin>>buf;
       CHECK_RET(sock.Send(buf,"172.17.0.4",9000));                                                                                                                   
       //4.接收数据
       buf.clear();
       CHECK_RET(sock.Recv(&buf));
       std::cout<<"server say:"<< buf<< "\n";
   }
   //5.关闭套接字
   sock.Close();
   return 0;
 }

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值