当前位置:网站首页>Socket programming UDP

Socket programming UDP

2022-06-12 11:22:00 Diligent_ wu

Network communication process simulation

 Insert picture description here
Quintuples : Each piece of data of a host must contain five pieces of information , Source end public network IP、 Source end port、 Peer to peer public network IP、 Opposite end port、 Protocol scheme

UDP Communication programming

udp Communication programming process :
 Insert picture description here

simulation socket Port binding process :
 Insert picture description here

socket Interface

int socket(int domain,int type,int protocol);
int bind(int sockfd,struct sockaddr* _addr,socklen_t len);
ssize_t recvfrom(int sockfd,char *buf,int len,int flag,struct sockaddr *peer_addr,socklen_t *addrlen )
ssize_t sendto(int sockfd,char* data,int len, int flag,struct sockaddr* peer_addr,socklen_t addlen);

1. Create socket

int socket(int domain,int type,int protocol);
domain:  Address field  -  Make sure this time socket Which protocol version of the address structure is used for communication  -  Different protocols have different address structures  -- AF_INET IPV4 Network protocol ;
type:  Socket type ( Streaming socket SOCK_STREAM /  Datagram socket SOCK_DGRAM(datagram) )	

protocol: Protocol type ( Generally, it is the choice of transport layer protocol IPPROTO_TCP = 6 /IPPROTO_UDP = 17) The default is 0,type After giving it ,protocol You can give 0 了 .
protocol stay /usr/include/netinet/in.h The following definition
Return value : Returns a file descriptor ( socket descriptor ) – Non-negative integer , Through this descriptor, you can find the corresponding socket Structure . Failure to return -1.

2. Binding address information for socket

int bind(int sockfd,struct sockaddr* _addr,socklen_t len);
sockfd:  Create the operation handle returned by the socket 
addr:  Address information to bind 
len: Length of address information to be bound 
 Return value : Bind successfully returned 0, Binding failed and returned -1.
 Address structure :(/usr/include/netinet/in.h:221、240)
struct sockaddr{
	sa_family_t sa_family;
	char  sa_data[4];
}

 Insert picture description here

struct sockaddr This structure , Contains two members , One is the address field , One is data .
We usually use AF_INET、AF_INET6 and AF_LOCAL fill , The three macros correspond to one structure , It contains different information . The first member of their structure is the same , Is an address field type , And you can bind different address information only by ensuring the address domain .
bind Different types can be bound , In order to achieve interface unification , So when the user defines the address structure , Define the address structure you need ( for example :ipv4 Just use struct sockaddr_in), But when Binding , Unification will force the type to sockaddr* type .
bind Internal implementation guess :

bind(fd,struct sockaddr* addr,len){
if(addr->sa_family == AF_INET){// binding IPV4 Address information , This structure follows sockadd_in To analyze }
	else if(addr->sa_family == AF_UNET6){//IPV6, according to IPV6 Address structure resolution }
	else if(addr->sa family == AF_LOCAL){}

3. receive data

 Not just receiving data , We also need to know who sent the data , In order to reply 
ssize_t recvfrom(int sockfd,char *buf,int len,int flag,struct sockaddr *peer_addr,socklen_t *addrlen )
sockfd: Socket operation handle 
buf: Receive buffer 
len: The length of data you want to accept 
flag: The default is 0, It means blocking . If there is no data , Just waiting for .
peer_addr: Address information of the sender 
addrlen: The length of the address information you want to get and the actual length returned ( Input/output parameter )
 Return value : The length of the actually received data bytes is returned successfully , Failure to return -1;

4. send data

ssize_t sendto(int sockfd,char* data,int len, int flag,struct sockaddr* peer_addr,socklen_t addlen);
data: The first address of the data to be sent 
peer_addr: The recipient's address information 
 Return value : The length of the actually received data bytes is returned successfully , Failure to return -1;

5. Close socket

close(int sockfd);

Byte order conversion interface

Conversion from host byte order to network byte order :

uint16_t htons(uint16_t data);	 Short 
uint32_t htonl(uint32_t data);	 Long integer 

Conversion from network byte order to host byte order :

uint16_t ntohs(unit16_t data);	 Short 
uint32_t ntohl(uint32_t data);	 Long integer 

character string IPV4 Of IP Address conversion to network byte order IP Address :

in_addr_t  It's a uint32_t type 
in_addr_t inet_addr(char* ip);

Integer of network byte order IP Address to string IPV4 Of IP Address :

char* inet_ntoa(struct in_addr_t nip);

Be careful :16 For bit conversion htons/ntohs
32 For bit conversion htonl/ntohl
Can't mix !!!
Will cause byte order disorder .
 Insert picture description here
4 Number of bytes used htons/ntohs, Only two bytes are cut out , Do byte order conversion , Then complete it , As a result, the data obtained are not in line with expectations . It's wrong. .
2 Number of bytes used htonl/ntohl, Carry out 4 Byte converted , Only two bytes will be completed first , It's changing , If you use 16 Bit data , Will only take the lower 16 A data . It's also wrong .

Simple and easy UDP Communication process

socket Class encapsulation
Encapsulates a udpSocket class , Every instantiated object is a udp Communication connection , Complete the communication process through the member methods of this object .

class udpSocket{
public:
	udpSocket():_sockfd(-1){}
	bool Socket();
	bool Bind(const str::string& ip,uint16_t port);
	bool Recvfrom(std::string* buf,std::string* ip,uint16_t* port);
	bool sendto(std::string& data,std::string& ip,uint16_t port);
	bool Close();
private:
	int _sockfd;
}
#include<cstdio>
#include<unistd.h>
#include<string>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

class UdpSocket
{
    
  public:
    UdpSocket():_sockfd(-1){
    }
  public:
    //1. Create socket 
    bool Socket()
    {
    
      //socket( Address field , Socket type , Protocol type )
      _sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      if(_sockfd < 0)
      {
    
        perror("socket error");
        return false;
      }
      return true;
    }
    //2. Binding address information 
    bool Bind(const std::string& ip,uint16_t port)
    {
    
      // Definition IPV4 Address structure information 
      struct sockaddr_in addr;
      addr.sin_family=AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      // Address structure size 
      socklen_t len = sizeof(struct sockaddr_in);
      //bind( socket descriptor , Address structure , Address structure size )
      int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
      if(ret < 0 )
      {
    
        perror("bind error");
        return false;
      }
      return true;
    }
    // receive data 
    bool Recvfrom(std::string* buf, std::string* ip = NULL,uint16_t* port = NULL)
    {
    
      // Create an address structure 
      struct sockaddr_in peer_addr;
      socklen_t len = sizeof(sockaddr_in);
      // Create buffer 
      char tmp[4096]={
    0};
      //recvfrom( socket descriptor , Receive buffer , Buffer size , identifier , Address structure information , Address structure size )
      ssize_t ret = recvfrom(_sockfd,tmp,4096,0,(struct sockaddr*)&peer_addr,&len) ;
      buf->assign(tmp,ret);          // from tmp Medium intercept ret The length of the data is put into buf in 
      if(ret < 0)
      {
    
        perror("recvfrom error");
        return false;
      }
      if(ip != NULL)
      {
    
        *ip = inet_ntoa(peer_addr.sin_addr);   // If it comes in ip yes NULL Of , Just put peer_addr Of ip Give it 
      }
      if(port!= NULL)
      {
    
        *port = ntohs(peer_addr.sin_port);
      }
      return true;
    }
    //4. send data 
    bool Sendto(std::string& data,std::string& ip,uint16_t port)
    {
    
      // Create an address structure 
      struct sockaddr_in peer_addr;
      peer_addr.sin_family = AF_INET;
      peer_addr.sin_port = htons(port);
      peer_addr.sin_addr.s_addr = inet_addr(ip.c_str());
      socklen_t len = sizeof(struct sockaddr_in);
      //sendto( Socket identifier , Send buffer , Buffer size , identifier , Address structure information , Address structure size )
      ssize_t ret = sendto(_sockfd,data.c_str(),data.size(),0,(struct sockaddr*)&peer_addr,len);
      if(ret < 0 )
      {
    
        perror("sendto error");
        return false;
      }
      return true;
    }
    //5. Close socket 
    bool Close()
    {
    
      if(_sockfd > 0 )
      {
    
        close(_sockfd);
        _sockfd = -1;
      }
      return true;
    }
  private:
    int _sockfd;
};

The communication process of the server

#include<iostream>
#include<string>
#include"Udpsocket.hpp"

#define CHECK_RET(p) if((p) == false){
      return false;}
int main(int argc, char*argv[])
{
    
  // Get orders 
  // ./udp_srv 192.168.116.128 9000
  if(argc != 3)
  {
    
    std::cout<<"Usage: ./udp_srv ip port";
    return -1;
  }
  uint16_t port = std::stoi(argv[2]);
  std::string ip = argv[1];

  // Demonstrate the socket server process 
  UdpSocket srv_socket;
  // Create socket 
  CHECK_RET(srv_socket.Socket());
  // Binding address information 
  CHECK_RET(srv_socket.Bind(ip,port));
  while(1)
  {
    
  // receive messages 
  std::string buf;
  std::string peer_ip;
  uint16_t peer_port;
  CHECK_RET(srv_socket.Recvfrom(&buf,&peer_ip,&peer_port));     // Accept peer address information 
  //clint[192.168.xxx.xxx 8000]say:
  std::cout<<"clint["<<peer_ip<<" "<<peer_port<<"]say:"<<buf<<std::endl;
  // Send a message 
  buf.clear();
  std::cout<<"server say:";
  std::cin>>buf;
  CHECK_RET(srv_socket.Sendto(buf,peer_ip,peer_port));          // Reply to whoever sends the data 
  }
  // Close socket 
  CHECK_RET(srv_socket.Close());
  return 0;
}

Client communication flow

#include<iostream>
#include<string>
#include"Udpsocket.hpp"
#define CHECK_RET(p) if((p) == false){
      return false;}
int main(int argc,char* argv[])
{
    
  if(argc != 3)
  {
    
    std::cout<<"Usage: ./udp_cli ip port";
    return -1;
  }
  std::string srv_ip = argv[1];
  uint16_t srv_port = std::stoi(argv[2]);


  UdpSocket cli_socket;
  CHECK_RET(cli_socket.Socket());
  //CHECK_RET(cli_socket.Bind(ip,port));
  while(1)
  {
    
    std::cout<<"client say:";
    std::string buf;
    std::cin>>buf;
    CHECK_RET(cli_socket.Sendto(buf,srv_ip,srv_port));
    buf.clear();
    CHECK_RET(cli_socket.Recvfrom(&buf));
    std::cout<<"server say: "<<buf<<std::endl;
  }
  CHECK_RET(cli_socket.Close());
  return 0;
}
原网站

版权声明
本文为[Diligent_ wu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/163/202206121110558464.html