Basics of network programming - UDP programming (2)

1 The concept of UDP

UDP is the abbreviation of User Datagram Protocol, and its Chinese name is User Datagram Protocol, which is a connectionless transport layer protocol in the OSI (Open System Interconnection, Open System Interconnection) reference model.
The UDP protocol, like the TCP protocol, is used to process data packets. In the OSI model, both are located at the transport layer, which is the upper layer of the IP protocol. UDP has the disadvantages of not providing data packet grouping, assembling and sorting of data packets, that is to say, after the message is sent, it is impossible to know whether it has arrived safely and completely. UDP is used to support network applications that need to transfer data between computers. Numerous client/server network applications, including network video conferencing systems, need to use the UDP protocol. The UDP protocol has been used for many years since its inception. Although its original brilliance has been overshadowed by some similar protocols, even today UDP is still a very practical and feasible network transport layer protocol.
Many applications only support UDP, such as: multimedia data flow, do not generate any additional data, and do not retransmit even if it is known that there is a damaged packet. When emphasizing transmission performance rather than transmission integrity, such as: audio and multimedia applications, UDP is the best choice. UDP is also a good choice when the data transmission time is so short that the previous connection process becomes the main body of the entire traffic.

2 UDP programming main functions and steps

1 socket

int socket(int domain, int type, int protocol);
功能:创建一个用来进程通信的套接字,返回文件描述符
参数:
	domain:AF_INET   	IPv4协议族
	type:SOCK_STREAM	流式套接字			tcp传输协议
		 SOCK_DGRAM		数据报套接字		udp传输协议
		 SOCK_RAW		原始套接字			
	protocol:默认为0 
返回值:
	成功返回套接字新文件描述符
	失败返回-1 

2 bind

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:将套接字与IP地址端口绑定在一起
参数:
	sockfd:文件描述符 
	addr:结构体空间首地址 
	addrlen:信息的长度
返回值:
	成功返回0 
	失败返回-1 

3 send two

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:给另一个套接字发送消息
参数:
	sockfd:套接字文件描述符
	buf:要发送数据存放空间的首地址
	len:要发送数据的长度
	flags:发送属性  默认为0 
	dest_addr:目的地址
	addrlen:目的地址信息长度
返回值:
	成功返回发送字节个数
	失败返回-1 

4 recvfrom

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
 功能:接收数据
参数:
	sockfd:套接字文件描述符
	buf:存放接收到数据空间的首地址
	len:最多允许接收的字节数
	flags:属性 默认为0 
	src_addr:存放发送端地址信息空间首地址
	addrlen:想要接收发送端地址大小的变量空间首地址
返回值:
	成功返回实际接收字节数
	失败返回-1 
**注意:该函数具有阻塞功能**

5 htons and ntohs

 uint16_t htons(uint16_t hostshort);
功能:将本地字节序转换为网络字节序
参数:hostshort:本地端口号
返回值:返回网络字节序端口号
uint16_t ntohs(uint16_t netshort);
功能:将网络字节序转换为本地字节序
参数:netshort:网络端口号
返回值:返回本地字节序端口号

6 socket structure

struct sockaddr_in {
    
    
	   sa_family_t    sin_family; /* address family: AF_INET */
	   in_port_t      sin_port;   /* port in network byte order */
	   struct in_addr sin_addr;   /* internet address */
   };

/* Internet address. */
struct in_addr {
    
    
	   uint32_t       s_addr;     /* address in network byte order */
   };

3 Use UDP programming to realize a single interaction between the client and the server polling

insert image description here
Here my ip address is 192.168.1.117 in the picture, so this address is used in all the codes below
insert image description here

head File

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/ip.h> 
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/epoll.h>

#endif

client code

#include "head.h"

int main(int argc, char const *argv[])
{
    
    
     // 初始化结构体套接字
     struct sockaddr_in cli;
     struct sockaddr_in ser = {
    
    
         .sin_family = AF_INET,
         .sin_port = htons(50000),
         .sin_addr.s_addr = inet_addr("192.168.1.117"),//这里你需要改为自己的ip
     };
     //==1==
     
     int sock_fd_a = socket(AF_INET, SOCK_DGRAM, 0);
     if (-1 == sock_fd_a)
     {
    
    
          perror("fail to socket");
          return -1;
     }
     while (1)
     {
    
    
          //==2==
          char sendbuf[1024] = {
    
    0};
          fgets(sendbuf, sizeof(sendbuf),stdin);
          ssize_t nret1 = sendto(sock_fd_a, sendbuf, strlen(sendbuf) + 1, 0, (struct sockaddr *)&ser, sizeof(ser));
          //==3==
          char recbuf[1024] = {
    
    0};
          ssize_t nret2 = recvfrom(sock_fd_a, recbuf, sizeof(recbuf), 0, NULL, NULL);
          printf("ser->cli:%s", recbuf);
     }
     //==4==
     close(sock_fd_a);

     return 0;
}

client code

#include "head.h"

int main(int argc, char const *argv[])
{
    
    
     // 初始化结构体套接字
     struct sockaddr_in cli;
     struct sockaddr_in ser = {
    
    
         .sin_family = AF_INET,
         .sin_port = htons(50000),
         .sin_addr.s_addr = inet_addr("192.168.1.117"),
     };
     //==1==
     int sock_fd_b = socket(AF_INET, SOCK_DGRAM, 0);
     if (-1 == sock_fd_b)
     {
    
    
          perror("fail to socket");
          return -1;
     }
     //==2==
     int bret = bind(sock_fd_b, (struct sockaddr *)&ser, sizeof(ser));
     if (-1 == bret)
     {
    
    
          perror("fail to bind");
          return -1;
     }
     while (1)
     {
    
    
          //==3==
          char recbuf[1024] = {
    
    0};
          socklen_t serlen = sizeof(ser);
          ssize_t nret2 = recvfrom(sock_fd_b, recbuf, sizeof(recbuf), 0, (struct sockaddr *)&ser, &serlen);
          printf("cli->ser:%s", recbuf);
          //==4==
          char sendbuf[1024] = {
    
    0};
          fgets(sendbuf, sizeof(sendbuf),stdin);
          ssize_t nret1 = sendto(sock_fd_b, sendbuf, strlen(sendbuf) + 1, 0, (struct sockaddr *)&ser, sizeof(ser));
     }
     close(sock_fd_b);

     return 0;
}

4 Use UDP programming to realize the file transfer between the client and the server (the picture file is used here, the header file is the same as the header file above, and the packet loss phenomenon of UDP is normal, and a little delay can be added to improve it)

Client (use some file io knowledge, mentioned in the previous blog)

#include "head.h"

int main(int argc, char const *argv[])
{
    
    
     struct stat file_stat;
     struct sockaddr_in cli;
     struct sockaddr_in ser = {
    
    
          .sin_family = AF_INET,
          .sin_port = htons(50000),
          .sin_addr.s_addr = inet_addr("192.168.1.117"),
     };
     

     int fd_src = open("./src.jpg",O_RDONLY);//打开文件
     if(-1 == fd_src)
     {
    
    
          perror("fail to open");
          return -1;
     }
     int stat_ret = fstat(fd_src,&file_stat);//获取文件状态
     if(-1 == stat_ret)
     {
    
    
          perror("fail to fstat");
          close(fd_src);
          return -1;
     }

     int fd_cli = socket(AF_INET,SOCK_DGRAM,0);
     if(-1 == fd_cli)
     {
    
    
          perror("fail to socket");
          return -1;
     }
     //发送文件大小
     sendto(fd_cli,&(file_stat.st_size),sizeof(&file_stat.st_size),0,(struct sockaddr *)&ser,sizeof(ser));
     printf("%ld\n",file_stat.st_size);
     char R_file_buf[1024] = {
    
    0};
     ssize_t nret = 0;
     while (1)
     {
    
    
          nret = read(fd_src,R_file_buf,sizeof(R_file_buf));
          printf("%ld\n",nret);
          if(nret <= 0)
          {
    
    
               break;
          }
          sendto(fd_cli,R_file_buf,nret,0,(struct sockaddr *)&ser,sizeof(ser));  
     }
     close(fd_src);
     return 0;
}

Server

#include "head.h"

int main(int argc, char const *argv[])
{
    
    
     struct sockaddr_in cli;
     struct sockaddr_in ser = {
    
    
          .sin_family = AF_INET,
          .sin_port = htons(50000),
          .sin_addr.s_addr = inet_addr("192.168.1.117"),
     };
     

     int fd_dst = open("./dst.jpg",O_RDWR | O_CREAT | O_TRUNC,0664);//打开文件
     if(-1 == fd_dst)
     {
    
    
          perror("fail to open");
          return -1;
     }
     int fd_ser = socket(AF_INET,SOCK_DGRAM,0);
     if(-1 == fd_ser)
     {
    
    
          perror("fail to socket");
          close(fd_dst);
          return -1;
     }
     int ret_bint = bind(fd_ser,(struct sockaddr *)&ser,sizeof(ser));
     if(-1 == ret_bint)
     {
    
    
          perror("fail to bind");
          close(fd_dst);
          return -1;
     }
     //接收文件大小
     char file_size[64] = {
    
    0};
     socklen_t clilen = sizeof(cli);
     ssize_t ret_re =  recvfrom(fd_ser,file_size,sizeof(file_size),0,(struct sockaddr *)&cli,&clilen);
     ssize_t size = 0;
     char tmpbuff[1024] = {
    
    0};
     while (1)
     {
    
    
         ssize_t nret =  recvfrom(fd_ser,tmpbuff,sizeof(tmpbuff),0,(struct sockaddr *)&cli,&clilen); 
         write(fd_dst,tmpbuff,nret);
         if(nret != 1024)
         {
    
    
          break;
         }
     }
     close(fd_ser);
     
}

result graph

insert image description here

5 The general framework of UDP programming

client Server
1 socket 1 socket
2 sentto 2 bind
3 recvfrom 3 recvfrom
4 close 4 sent two
5close

Guess you like

Origin blog.csdn.net/m0_58193842/article/details/128708279