[school recruitment -- phase II network programming] UDP socket programming

1, Preparatory knowledge

1. Understand source IP address and destination IP address

There are two IP addresses in the IP packet, one is the source IP address and the other is the destination IP address. IP address is responsible for transmitting data from one host hardware to another host hardware. IP address identifies the uniqueness of the whole network and hardware of this host

2 port number

ip address is the only host in the whole network, and a host has many processes, so the port number is used to identify a specific process in the main sentence. Therefore, ip address + port number = the only process in the whole network (ip + port number is called socket)

3 Relationship between port number and process ID

We learned in system programming that each process has a unique Id called pid, and the port number here is also the only description of a process.
The PID of the process is required. Only the network process has a port number.
A port number can only be occupied by one process The port number is used to identify a process and tell the operating system to which process the current data is to be processed; A process binds multiple port numbers, but a port number cannot be bound by multiple processes.

4 source port number and destination port number

There are two port numbers in the data segment of transport layer protocol (TCP and UDP), which are called source port number and destination port number respectively It's describing "who sent the data and what to do
To whom ";

5 TCP and UDP protocols

tcp
characteristic:

Transport layer protocol
Connected
Reliable transmission
Byte oriented stream

udp
characteristic:

Transport layer protocol
No connection
Unreliable transmission
Datagram oriented

Compared with tcp, udp has faster transmission efficiency.

6 network byte order

Previously, we learned that data storage can be divided into large and small ends, and different hosts can also be divided into large and small ends. Therefore, in the process of network transmission, if the source host is a large end and then transmits data, and the destination host is a small end machine, and we don't know that the source host will interpret the data incorrectly, so how to solve it? The network stipulates that all data running on the network is big. The data will be sent by the TCP/IP host or the small host in the order specified by the network; If the current sending host is a small end, you need to convert the data to a large end first; Otherwise, ignore it and send it directly; The sending host usually sends the data in the sending buffer in the order of memory address from low to high; The receiving host saves the bytes received from the network in the receiving buffer in turn, which is also saved in the order of memory address from low to high; Therefore, the address of network data flow should be specified as follows: the data sent first is the low address, and the data sent later is the high address TCP/IP protocol stipulates that the network data flow shall adopt large end byte order, that is, low address and high byte


In order to make the network program portable and make the same C code run normally after being compiled on the big end and small end computers, the following library functions can be called to convert the network byte order and the host byte order.

These function names are easy to remember. h represents host,n represents network,l represents 32-bit long integer and s represents 16 bit short integer.
For example, htonl means to convert a 32-bit long integer from host byte order to network byte order. For example, after converting the IP address, it is ready to be sent.
If the host is in small end byte order, these functions convert the parameters to large and small end and then return;
If the host is large endian, these functions do not convert and return the parameters intact.

2, socket common interface

sockaddr structure

socket API is an abstract network programming interface, which is applicable to various underlying network protocols, such as IPv4, IPv6 and UNIX Domain
Socket. However, the address formats of various network protocols are different In order to use a set of interface socket interface to complete the communication between all kinds of sockets or different kinds of sockets, the operating system designs sockaddr in order to meet this requirement


There is a 16 bit address type in the same structure of these three. The common structure of socket is the second kind of struct sockaddr_in, the 16 bit port number and 32-bit IP address are called sockets. The parameters in the common socket interface are this struct sockaddr* address, but we often use struct sockaddr_ The structure of in only needs to be forcibly converted to struct sockaddr in the process of parameter transmission. This is to complete the conversion of different programs with a set of interfaces. When struct sockaddr is passed in_ In uses the communication mode of IPV4. When the third structure is passed in, it uses the communication mode of IPV6.

socket common API

Header file:
#include<sys/types.h>
#include<sys/socket.h>

//Create socket file descriptor (TCP/UDP, client + server)
int socket(int domain, int type, int protocol);
Parameters:
domian: which protocol is used, AF_INET(IPV4) is often used, AF_INET6(IPV6)
Type socket type, sock_ Stream (upper case streaming socket), sock_ Dgran (upper case user datagram socket)
protocol defaults to 0

Its return value is a file descriptor, because all files are connected in linux. To realize network communication, first open the network card device and create the required data structures. These data structures are also files in linux.
Creating a socket is to open a network file after opening a file. This is a process, which becomes a network process. When communicating, the network process must have a port number bound to it to bind the system information and IP address.

//Binding port number (TCP/UDP, server)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
Parameters:
socket opens the file descriptor of the network file
Struct socketaddr: the parameter is usually struct socketaddr_in type includes IP address and port number
address_len: the length corresponding to the incoming address.

If the function is executed successfully, it returns 0, otherwise it returns - 1, and sets the error code
socketaddr_in structure

sin_family is a protocol family and adopts IPV4, so the general value is AF_INET, where In_port is the 16 bit port number, in_addr is a structure
In_addr structure

s_addr is a 32-bit IP address

Because udp socket communication does not need to establish a connection, it can send and receive files directly.

For acceptance
ssize_t recvform(int sockfd,voidbuff,size_t len,int flags,struct sockaddrsrc_addr,socklen_t *addrlen);
Parameters;
sockfd is a file descriptor. buf reads the data buffer. The number of data len expects to read represents the size of the buffer. flags read data belongs to io read data, and there may not be data readable (when the read condition is not established, the process will wait for blocking, and 0 is the blocking state by default). Src in the back_ Addr and addrlen are output parameters, including the IP address and source port of the active host

For sending
ssize_t sendto(int sockfd,const void buff,size_t len,int flags,struct sockaddrsrc_addr,socklen_t *addrlen);
Parameters:
sockfd is a file descriptor. buff indicates the content of the occurrence, len the length of the occurrence data, flags the write data belongs to io, and the write data may not be writable (when the write condition is not established, the process will wait for blocking, and 0 is the blocking state by default)_ Addr and addrlen are input parameters, including the IP address and source port of the active host

#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<iostream>
#include<string>
using namespace std;
class SocketSever{
private:
//string ip;
int post;
int sock;//File descriptor, create socket return value
public:
SocketSever(int _post=8080):
post(_post)
{
}
void Init(){

sock=socket(AF_INET,SOCK_DGRAM,0);
cout<<"sock:"<<sock<<endl;
struct sockaddr_in in_addr;//The IP address and port number are bound at the kernel level
in_addr.sin_family=AF_INET;//The set protocol family is generally AF_INET IPV4
in_addr.sin_port=htons(post);//The communication port should be set as the network serial number
//in_addr.sin_addr.s_addr=inet_addr(ip.c_str());// Set the IP address and convert the string IP into the dotted decimal network IP address, because string is a class and INET_ The addr parameter is a string, so C is used_ Str() conversion.
in_addr.sin_addr.s_addr=INADDR_ANY;
if(bind(sock,(const struct sockaddr*)&in_addr,sizeof(in_addr))<0){

cout<<"Binding failed..."<<endl;
exit(1);
}
}
void star(){
 char buff[64];
while(1){
struct sockaddr_in addr;
socklen_t len=sizeof(addr);//Actual read size
ssize_t size=recvfrom(sock,buff,sizeof(buff)-1,0,(struct sockaddr*)&addr,&len);//accept
if(size>0){
buff[size]=0;
cout<<"client:"<<buff<<endl;
string str="sever Data has been received...";
size_t s=sendto(sock,str.c_str(),sizeof(str)-1,0,(struct sockaddr*)&addr,len);
}	
}
}
~SocketSever(){
close(sock);
}
};
int main(int argc,char *argv[]){
SocketSever ss(atoi(argv[2]));
ss.Init();
ss.star();
	
return 0;
}
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<iostream>
#include<string>
using namespace std;
class Socketclient{
private:
string ip;
int post;
int sock;//File descriptor, create socket return value
public:
//IP is the IP address and port number of the corresponding client
Socketclient(string ip_="127.0.0.1",int _post=8080):
ip(ip_),
post(_post)
{
}
//The client does not need to bind, just create a socket
void Init(){

sock=socket(AF_INET,SOCK_DGRAM,0);
cout<<"sock:"<<sock<<endl;
//struct sockaddr_ in in_ addr;// The IP address and port number are bound at the kernel level
//in_addr.sin_family=AF_INET;// The set protocol family is generally AF_INET IPV4
//in_addr.sin_port=htons(post);// Set the port number. Because it is network communication, it is necessary to convert the host sequence into network sequence
//in_addr.sin_addr.s_addr=inet_addr(ip.c_str());// Set the IP address and convert the string IP into the dotted decimal network IP address, because string is a class and INET_ The addr parameter is a string, so C is used_ Str() conversion.
//if(bind(sock,(const struct sockaddr*)&in_addr,sizeof(in_addr))<0){

//Cout < < "bind failed..."<< endl;
//exit(1);
//}
}
//Client refers to receiving before sending, and client refers to sending before receiving
void star(){
 //char buff[64];
 string str;
while(1){
cout<<"Please enter the content to send:";
cin>>str;
struct sockaddr_in in_addr;//The IP address and port number are bound at the kernel level
in_addr.sin_family=AF_INET;//The set protocol family is generally AF_INET IPV4

in_addr.sin_port=htons(post);//Set the port number because it is required for network communication
in_addr.sin_addr.s_addr=inet_addr(ip.c_str());//Set the IP address and convert the string IP into the dotted decimal network IP address, because string is a class and INET_ The addr parameter is a string, so C is used_ Str() conversion. To convert the host sequence into a network sequence
//
size_t s=sendto(sock,str.c_str(),sizeof(str)-1,0,(struct sockaddr*)&in_addr,sizeof(in_addr));
if(s<0){
cout<<"Transmission error"<<endl;
}
char buff[64];
struct sockaddr_in addr;
socklen_t t=sizeof(addr);
ssize_t size=recvfrom(sock,buff,sizeof(buff)-1,0,(struct sockaddr*)&addr,&t);
if(size>0){
buff[size]=0;
cout<<"Server feedback..."<<endl;
}
}

//struct sockaddr_in addr;
//socklen_ t t struct sockaddr*)&in_ addr,sizeof(in_addr)en=sizeof(addr);// Actual read size
//ssize_ t size=recvfrom(sock,buff,sizeof(buff)-1,0,(struct sockaddr*)&addr,&len);// accept
//if(size>0){
//buff[size]=0;
//cout<<"client:"<<buff<<endl;
//string str="client has received data...";
//size_t s=sendto(sock,str.c_str(),sizeof(str)-1,0,(struct sockaddr*)&addr,len);
//}	
//}
}
~Socketclient(){
close(sock);
}
};
void up(string str){
cout<<str<<"Please enter IP Address and port number"<<endl;

}

int main(int argc,char *argv[]){
if(argc!=3){
up(argv[0]);
exit(1);
}

Socketclient ss(argv[1],atoi(argv[2]));
ss.Init();
ss.star();
	
return 0;
}


explain:

Generally, sever's IP address and post cannot be easily changed. It is well known that it is certain, because once changed, the client will not be connected
The client does not need strong bind, but needs IP and post. Why not bind?
When you bind, it is easy to cause the client to fail to start
2 the client needs a unique port number, but it does not need to specify which port number is required
However, if you need udp, recv and send of IP and port:client, the system will automatically bind IP and port number.

Keywords: Linux network udp TCP/IP

Added by neal.pressley on Tue, 08 Mar 2022 17:58:56 +0200