❤️ Angry liver 30000 words, epic nanny, network programming teaching ❤️

Network programming concepts

Network communication is to solve the communication between different host processes
1. The primary problem is the identification of processes between networks
2. As well as the identification of multiple protocols, its network program development interface is socket. With the wide application of UNIX and UNIX like operating systems, socket has become the most popular network program development interface
socket function
Provides communication between processes on different hosts
socket features
1. Socket is also called "socket"
2. Is a file descriptor that represents an endpoint of a communication pipeline
3. Similar to the operation of files, you can use read, write, close and other functions to collect and send network data to socket s
4. The method that gets the socket (descriptor) calls socket()

1. Byte order

Concept: refers to the storage order of multi byte data
Classification:
1. Large end (store high byte data in low address)
2: Small end (store low byte data in low address)

2. Byte order conversion

Host byte order to network byte order (network byte order defaults to large end, while most hosts are small end)
uint32_t htonl(uint32_t hostint32);//
uint16_t htons(uint16_t hostint16);

3. Network byte order - host byte order

uint32_t ntohl(uint32_t netint32);
uint16_t ntohs(uint16_t netint16);

1. The network byte order is always the big end, and the conversion of host byte order to network byte order is to save the big end, and the conversion of network byte order to host byte order is to convert the big end to the big end / small end.
2. Byte order needs to be considered only in multi byte data processing.
3. Network process communication between the same host does not require byte order conversion.
4. Network process communication between different hosts requires byte order conversion.

4. Address translation function

Dotted decimal to integer
int inet_pton(int family,const char *strptr, void *addrptr);
parameter
1,protocol family AF_INET
2,Dotted decimal string
3,Integer after conversion
 Return value: 1 success
Converts a 32-bit unsigned integer to a dotted decimal string
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
parameter
1,protocol family AF_INET
2,32 Bit unsigned integer
3,Dotted decimal string
4,Length of dotted decimal string buffer (16)
Return value: successful:Failed to return the first address of the string:return NULL

UDP programming

1. Concept

For connectionless user datagram protocol, there is no need to establish a connection before transmitting data; The transport layer of the destination host does not need to give any confirmation after receiving the UDP message
characteristic:
1. Slightly faster than TCP
2. Simple request / reply applications can use UDP
3. UDP should not be used for mass data transmission
4. Broadcast and multicast applications must use UDP
Applications: DNS (domain name resolution), NFS (network file system), RTP (streaming media), etc



-UDP communication process

UDP programming core code introduction

Send data - sendto function

 Send data - sendto function
ssize_t sendto(int sockfd,const void *buf,
 size_t nbytes,int flags,
 const struct sockaddr *to, 
 socklen_t addrlen);
Function: to to Specified in structure pointer ip,send out UDP data
 Parameters: 
sockfd: socket
buf:  Send data buffer
nbytes: Size of send data buffer
flags: Generally 0
to: Pointer to the destination host address structure
addrlen: to Length of content pointed to
 be careful: 
adopt to and addrlen Determine destination address
 Can send 0 length UDP data packet
 Return value:

bind function

UDP What conditions do network programs need to collect data?
affirmatory ip address
 affirmatory port
 How to complete the above conditions?
Receiver use bind Function to complete the address structure and socket Socket binding, so ip,port It's fixed
 Sender at sendto Function to specify the of the receiving end ip,port,You can send data
int bind(int sockfd,
const struct sockaddr *myaddr,socklen_t addrlen);
Function: compare the local protocol address with sockfd binding
 Parameters: 
sockfd:  socket socket
myaddr:  Pointer to the address structure of a specific protocol
addrlen: The length of the address structure
 Return value: 
Success: return 0
 Failed: other

Introduction to recvform function

Receive data - recvfrom function
ssize_t recvfrom(int sockfd, void *buf,
size_t nbytes,int flags,
 struct sockaddr *from, 
 socklen_t *addrlen);
Function: 
receive UDP Data and save the source address information in from In the structure pointed to
 Parameters: 
sockfd: socket
buf: Receive data buffer
nbytes:Size of receive data buffer
flags:  Socket flag(Usually 0)
from:  Source address structure pointer, which is used to save the source of data
addrlen: from Length of content
 be careful: 
adopt from and addrlen Parameter storage data source information
from and addrlen Can be NULL, Indicates that the data source is not saved
 Return value: 
success:Number of characters received
 fail: -1

2.UDP simple client code demonstration

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc ,char **argv)
{
    //Creating a socket is essentially a file descriptor
     struct sockaddr_in det;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    printf("sockfd = %d\n", sockfd);

    //Specify who to send to and bind to the destination host
    det.sin_family = AF_INET;
    det.sin_port = htons(8888);
    inet_pton(AF_INET, argv[1],&det.sin_addr);
    memset(det.sin_zero, 0, 8);
    printf("%u,%u\n", det.sin_addr, det.sin_port);
    // int err = bind(sockfd, (struct sockadd *)&det, sizeof(det));
    // if(err < 0)
    // {
    //     printf("bind error\n");
    // }
    while(1)
    {
        int fd = fork();
        if(fd == 0)
        {
            char buf[50];
            socklen_t form_S = sizeof(det);
            recvfrom(sockfd, buf, sizeof(buf),0,(struct sockaddr*)&det,&form_S);
            printf("from server:%s\n",buf);
        }
        else
        {
            char *buf = (char *)malloc(20);
            fgets(buf, 20, stdin);
            *(buf + strlen(buf) - 1) = '\0';
            int a = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&det, sizeof(det));
            printf("send num:%d\n", a);

            if (strcmp(buf, "bye") == 0)
            {
                break;
            }
        }
        
    
    }
}

UDP simple server code demonstration

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc ,char **argv)
{
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    int pipe_fd[2];
    pipe(pipe_fd);
    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(10086);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int err = bind(sock_fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
    if(err == -1)
    {
        printf("bind error\n");
    }

    while(1)
    {
        int fd = fork();
        if(fd ==0)
        {
            char buf[20];
            unsigned int client_ip;
            char from_ip[16]=" ";
            struct sockaddr_in client_addr;
            socklen_t  addrlen=sizeof(client_addr);
            client_addr.sin_family = AF_INET;
            client_addr.sin_port = htons(10086);
            read(pipe_fd[0],  (void *)&client_addr.sin_addr, sizeof( client_addr.sin_addr));
           // inet_pton(AF_INET, "10.36.145.41",&client_addr.sin_addr);
            printf("recevie :%s\n",from_ip);
            while(1)
            {
                memset(buf, 0, sizeof(buf));
                fgets(buf, sizeof(buf), stdin);
                int err = sendto(sock_fd, buf, strlen(buf), 0,(struct sockaddr *)&client_addr, addrlen);
                printf("Data sent%d\n", err);
            }
        }
        else
        {
        char buf[20];
        char from_ip[16]=" ";
        struct sockaddr_in from_addr;
        bzero(&from_addr,sizeof(from_addr));
        memset(buf, 0, sizeof(buf));
        memset(from_ip, 0, sizeof(from_ip));
        socklen_t  addrlen=sizeof(from_addr);

        //Source ip received
        recvfrom(sock_fd, buf, 20, 0, (struct sockaddr *)&from_addr,&addrlen);
        write(pipe_fd[1], (void *)&from_addr.sin_addr.s_addr, sizeof(from_addr.sin_addr.s_addr));
        //Resolve the address of the source ip
        inet_ntop(AF_INET, (const void *)&from_addr.sin_addr.s_addr, from_ip,(socklen_t)16);
        printf("receive from :%s\n", from_ip);
        printf("buf :%s\n", buf);
       // sendto(sock_fd, buf, sizeof(buf), 0, (struct sockaddr *)&from_addr, addrlen);
        }
    }

}

Implementation of UDP broadcast function

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */

/*This is a broadcast program. How to broadcast all hosts to the LAN is limited to the LAN
,Man and WAN are not applicable because they have too many host ip    
*/
#if 0
int main(int argc,char**argv)
{
    struct sockaddr_in det;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    printf("sockfd = %d\n", sockfd);

    //Change the mac address to full f and modify the socket to allow broadcast messages to be sent
    int yes = 1;
     setsockopt(sockfd, SOL_SOCKET,SO_BROADCAST, &yes, sizeof(yes));

    //Designated broadcast
    det.sin_family = AF_INET;
    det.sin_port = htons(8080);
    socklen_t addrlen = sizeof(det);
    inet_pton(AF_INET, argv[1],&det.sin_addr);
    memset(det.sin_zero, 0, 8);
    printf("%u,%u\n", det.sin_addr.s_addr, det.sin_port);

    

    
    while(1)
    {
        char buf[64] = " ";
        fgets(buf, sizeof(buf), stdin);
        sendto(sockfd, buf,sizeof(buf), 0, (const struct sockaddr *)&det, addrlen);
    }
}
#endif

Implementation of UDP multicast function

/*
This is a basic demonstration program of udp multicast
*/
int main(int argc,char**argv)
{
    struct sockaddr_in det;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    printf("sockfd = %d\n", sockfd);

    char group[INET_ADDRSTRLEN] = "224.0.1.1";

    //Define a multicast address
    struct ip_mreq mrep;

    //Add a multicast group IP
    mrep.imr_multiaddr.s_addr = inet_addr(group);

    //Add an ip that will be added to the multicast group
    mrep.imr_interface.s_addr = htons(INADDR_ANY);

    setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mrep, sizeof(mrep));

    //assignment
    det.sin_family = AF_INET;
    det.sin_port = htons(8080);

    /*The conversion is 0.0.0.0, which generally means native
    ,This means all IP addresses of this machine, because some machines have more than one network card. In the case of multiple network cards,
    This means the ip addresses of all network cards.
    For example, a computer has three network cards, which are connected to three networks respectively,
    So this computer has three ip addresses. If an application needs to listen to a port, which network card address should it listen to?*/
    det.sin_addr.s_addr = htons(INADDR_ANY);//Add your own local ip address
    socklen_t addrlen = sizeof(det);   
    memset(det.sin_zero, 0, 8);

    //binding
    bind(sockfd, (const struct sockaddr *)&det, addrlen);

    while(1)
    {
        char buf[64] = "";
        recvfrom(sockfd, buf, sizeof(buf), 0, NULL,NULL);
        printf("rece:%s\n", buf);
    }
}
/*
Multicast experiment summary
1.First add the current ip address to the multicast group address, and then send the message to 224.0.1.1 when the client sends the message
 The message will be sent to all ip that join the multicast group. If you don't want to, you can also remove the ip address from the multicast group
*/

Introduction to TFTP protocol

1.1 TFTP overview

TFTP: simple file transfer protocol
Originally used to boot diskless systems, it was designed to transfer small files

characteristic:
Implementation based on UDP protocol
No user validity authentication

Data transmission mode:
octet: binary mode
netascii: text mode
mail: no longer supported

4.1.2 TFTP communication process

  1. . the server receives the client's read / write request from the fixed port 69
  2. After receiving the request, the server uses a temporary port to send data packets to the client, which is fixed to 512 bytes, or the length of fixed bytes can be changed
  3. After receiving the data, the client sends an ack saying that I have received it
  4. If the data packet sent by the server is less than 512 bytes, it means that the data sent by the server has been sent, and the transmission ends

1.3 TFTP protocol analysis

1.4 simple process of client file download

  1. Create udp socket
  2. The packet of group read request (0, 1, "file name", 0, "mode", 0) is sent to the server
  3. Receive data circularly. If the data packet buf length is less than 516, exit, otherwise continue
  4. View the data packet buf [1], if buf[1] == 3; Write documents and reply ack; buf[1] == 5;break;

1.5 simple process of uploading files from the client

  1. Create socket
  2. Packet of group write request (0,1, "file name", 0, "mode", 0)
  3. The client opens the file to upload
  4. Send data buf circularly. If the read local file length is less than 512, break;

1.6 TFTP files with options

tsize option
When reading, the parameter of tsize option must be "0", and the server will return the size of the file to be read
When writing, the tsize option parameter should be the size of the file to be written, and the server will echo this option
blksize option
Modify the size of the data block used when transferring files (range: 8 ~ 65464)
timeout option
Modify the default data transmission timeout (unit: seconds)

TFTP communication process summary (with options)

1. You can send a read / write request with options to the server
2. If the server allows you to modify options, send an option modification confirmation package
3. The data and option modification confirmation package sent by the server are temporary port s
4. The server resends lost packets through timeout

Code demonstration of TFTP download process (without option)

Let's demonstrate how to download the files you want from the server and save them in it
It implements TFTP client download and upload functions,
TFTP software download link
We need to do experiments with this software

#include <stdio.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[]){
	//Create socket
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0){
		printf("Creation failed\n");
		return 0;
		}
	else{
		printf("Created successfully %d\n",sockfd);
	}
	//Send download request to server
	struct sockaddr_in ser_addr;
	bzero(&ser_addr,sizeof(ser_addr));
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_port=htons(69);
	inet_pton(AF_INET,"10.36.145.220",(void *)&ser_addr.sin_addr);
	char buf[64]="";
	int buf_len=sprintf(buf,"%c%c%s%c%s%c",0,1,"a.txt",0,"netascii",0);
	sendto(sockfd,buf,buf_len,0,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
	//Open a local file to receive server data
	int fd = open("a.txt",O_RDWR|O_CREAT,0666);
	if(fd<0){
		perror("open");
		return 0;
		}
	
	//Receive packet
	char rcv_buf[1024]="";
	int rcv_buf_len=0;
	struct sockaddr_in from_addr;
	socklen_t addrlen=sizeof(from_addr);
	while(1){
		//Receive data function
		bzero(&from_addr,sizeof(from_addr));
		rcv_buf_len=	recvfrom(sockfd, rcv_buf, sizeof(rcv_buf),0,(struct sockaddr*)&from_addr,&addrlen);
		if(rcv_buf[1]==5)//error
		{
			printf("error:%d-%d%s\n",rcv_buf[2],rcv_buf[3],rcv_buf+4);
			break;
		}
		else if(rcv_buf[1]==3)//data packet
		{
			//Write file
			write(fd,rcv_buf+4,rcv_buf_len-4);
			//Reply ACK
			rcv_buf[1]=4;
			sendto(sockfd,rcv_buf,4,0,(struct sockaddr *)&from_addr,sizeof(from_addr));
			if(rcv_buf_len<516)
				break;
		}
		else;
	}
	
	close(sockfd);
	close(fd);
	
	return 0;
}

Code demonstration of TFTP upload process (without options)

#include <stdio.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[]){
	//Create socket
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0){
		printf("Creation failed\n");
		return 0;
		}
	else{
		printf("Created successfully %d\n",sockfd);
	}
	//Send upload request to server
	struct sockaddr_in ser_addr;
	bzero(&ser_addr,sizeof(ser_addr));
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_port=htons(69);
	inet_pton(AF_INET,"10.36.145.220",(void *)&ser_addr.sin_addr);
	char buf[64]="";
	int buf_len=sprintf(buf,"%c%c%s%c%s%c",0,2,"a.txt",0,"netascii",0);
	sendto(sockfd,buf,buf_len,0,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
	//Open local file
	int fd = open("a.txt",O_RDWR);
	if(fd<0){
		perror("open");
		return 0;
		}
	
	//Receive packet
	char rcv_buf[1024]="";
	int rcv_buf_len=0;
	unsigned short p_num=0;
	struct sockaddr_in from_addr;//Temporary port used to store server ip and server
	socklen_t addrlen=sizeof(from_addr);
	while(1){
		//Receive data function
		bzero(&from_addr,sizeof(from_addr));
		recvfrom(sockfd, rcv_buf, sizeof(rcv_buf),0,(struct sockaddr*)&from_addr,&addrlen);
		if(rcv_buf[1]==5)//error
		{
			printf("error:%s\n",rcv_buf+4);
			break;
		}
		else if(rcv_buf[1]==4)//ACK   0 4 0 0-------0 3 0 1 512byte
		{
			//Read local files
			rcv_buf_len=	read(fd,rcv_buf+4,512);// 0 4 0 0-------0 4 0 0 512byte
			rcv_buf[1]=3;// 0 4 0 0-------0 3 0 0 512byte
			p_num=ntohs(*(unsigned short *)(rcv_buf+2));//Take RCV_ 3 ~ 4 bytes of buf and save to the host
			*(unsigned short *)(rcv_buf+2)=htons(p_num+1);
			//Assign the number of ack packet + 1 to packet 0 4 0 x-------0 3 0 x+1 512byte
			printf("Packet number to be sent:%d\n",p_num+1);
			sendto(sockfd,rcv_buf,rcv_buf_len+4,0,(struct sockaddr *)&from_addr,sizeof(from_addr));
			if(rcv_buf_len<512)
				break;
		}
		else;
	}
	
	close(sockfd);
	close(fd);
	
	return 0;
}

Code demonstration of TFTP download process (with options)

The advantage of this option is that you can modify the packet size, ack timeout or other information sent each time.

#include <stdio.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[]){
	//Create socket
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0){
		printf("Creation failed\n");
		return 0;
		}
	else{
		printf("Created successfully %d\n",sockfd);
	}
	//Send download request to server
	struct sockaddr_in ser_addr;
	bzero(&ser_addr,sizeof(ser_addr));
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_port=htons(69);
	inet_pton(AF_INET,"10.36.145.220",(void *)&ser_addr.sin_addr);
	char buf[64]="";
	int buf_len=sprintf(buf,"%c%c%s%c%s%c%s%c%s%c",0,1,"a.txt",0,"netascii",0,"blksize",0,"1024",0);//Send request with options
	sendto(sockfd,buf,buf_len,0,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
	
	
	
	//Open a local file to receive server data
	int fd = open("a.txt",O_RDWR|O_CREAT,0666);
	if(fd<0){
		perror("open");
		return 0;
		}
	
	//Receive packet
	char rcv_buf[1056]="";
	int rcv_buf_len=0;
	int len=0;
	unsigned short p_num=0;
	struct sockaddr_in from_addr;
	socklen_t addrlen=sizeof(from_addr);
	
	
	//Accept OACK
	
	recvfrom(sockfd, rcv_buf, sizeof(rcv_buf),0,(struct sockaddr*)&from_addr,&addrlen);
	if(rcv_buf[1]==6)//0 6 option 0 value 0 
	{
		rcv_buf[1]=4;//0 4 option 0 value 0 
		rcv_buf[2]=0;//0 4 0 0 0 value 0 
		rcv_buf[3]=0;//0 4 0 0 0 value 0 
		sendto(sockfd,rcv_buf,4,0,(struct sockaddr *)&from_addr,sizeof(from_addr));
	}
	else{
		return 0;
	}
	
	while(1){
		//Receive data function
		bzero(&from_addr,sizeof(from_addr));
		rcv_buf_len=	recvfrom(sockfd, rcv_buf, sizeof(rcv_buf),0,(struct sockaddr*)&from_addr,&addrlen);
		if(rcv_buf[1]==5)//error
		{
			printf("error:%s\n",rcv_buf+4);
			break;
		}
		else if(rcv_buf[1]==3)//data packet
		{
			//Write file
			len=write(fd,rcv_buf+4,rcv_buf_len-4);
			//Print packet number
			p_num=ntohs(*(unsigned short * )(rcv_buf+2));
			printf("Package No.:%d   --- %d\n",p_num,len);
			//Reply ACK
			rcv_buf[1]=4;
			sendto(sockfd,rcv_buf,4,0,(struct sockaddr *)&from_addr,sizeof(from_addr));
			if(rcv_buf_len<1028)
				break;
		}
		else;
	}
	
	close(sockfd);
	close(fd);
	
	return 0;
}

Code demonstration of TFTP upload process (with options)

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>


//Upload with options on the client
#if 1
      int main(int argc,char**argv)
    {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    int p_num;
    char buf[64] ;
    char rece_buf[1056] =" ";
    printf("sockfd = %d\n", sockfd);
    struct sockaddr_in det;
    struct sockaddr_in server;


    //Judge whether parameters are carried during execution
    if(argc<2)
    {
        printf("You have not specified a server ip address\n");
        return 0 ;
    }

    //Specify who to send to and bind to the destination host
      bzero(&det,sizeof(det));
    det.sin_family = AF_INET;
    det.sin_port = htons(69);
    inet_pton(AF_INET, argv[1],&det.sin_addr);
    memset(det.sin_zero, 0, 8);
    printf("%u,%u\n", det.sin_addr.s_addr, det.sin_port);
    socklen_t addrlen = sizeof(det);



    //Create a receive file downloaded from the server
   

          //Assemble and send packets
            int buflen = sprintf(buf,"%c%c%s%c%s%c%s%c%s%c",0,2,"up.txt",0,"netascii",0,"blksize",0,"1024",0);//The size of the data packet should be correct and cannot be transmitted too much 
            int sendnum = sendto(sockfd, buf,buflen, 0, (const struct sockaddr *)&det, addrlen);
                printf("send num %d \n",sendnum);
            int fd = open("a.txt", O_RDWR | O_CREAT, 0666);
            if(fd<1)
            {
                printf("open error \n");
                return 0 ;
            }

            //Wait for a response from the server osak
              char oask_buf[1056]="";
            int rece_osk_num = recvfrom(sockfd, oask_buf, sizeof(oask_buf), 0, ( struct sockaddr *)&server, &addrlen);
          if(oask_buf[1]!=6)
          {
              printf("Reply failed\n");
              return 0;
          }
  
    while(1)
        {
                //Read data
               int recebuf_len =  read(fd, rece_buf + 4, 1028);

                 //Changing the opcode to 3 means sending a reply command 0 to the server
                rece_buf[1] = 3;
                 p_num = ntohs(*(unsigned short *)(rece_buf + 2));
                 *(unsigned short *)(rece_buf + 2) = htons(p_num + 1);
                 printf("Number to be sent:%d\n", p_num + 1);
                sendto(sockfd, rece_buf,recebuf_len+4, 0,(const struct sockaddr *)&server, addrlen);//The destination ip and source port should be used when sending, because the temporary port is used, so be careful

          
            //Judge whether the received byte is less than 1028. If it is less than 1028, it ends
                        if(recebuf_len<1028)
                    {

                        printf("File transfer complete\n");
                        break;
                    }
        // memset(oask_buf, 0, sizeof(oask_buf));
                  
                    // recvfrom(sockfd, oask_buf, sizeof(oask_buf), 0, (struct sockaddr *)&server, &addrlen);
                    // if (oask_buf[1] == 5)
                    // {
                    //     printf("error :%s\n", oask_buf + 4);
                    //  }
                    // else if(oask_buf[1] == 4)
                    // {
                    //     printf("server response \ n");

                    // }
            
            
        }

    close(sockfd);
	close(fd);
    }  
#endif

TCP network programming

TCP features:

1. Connection oriented streaming protocol; Reliable, error retransmission, and corresponding confirmation shall be given for each data received
2. A link needs to be established before communication
3. The server is a passive link, and the client is an active link

TCP client and server processes

socket function (required for client and server)

iint socket(int family,int type,int protocol); 
Function: create a for network communication socket Socket (descriptor)
 Parameters:
 	family:protocol family(AF_INET,AF_INET6,PF_PACKET etc.),Commonly used AF_INET,in the light of internet of
    type:Socket class(SOCK_STREAM,SOCK_DGRAM,SOCK_RAW etc.)
    	SOCK_STREAM: representative TCP agreement
    	SOCK_DGRAM :express UDP agreement
    protocol:Protocol category(0,IPPROTO_TCP,IPPROTO_UDP And so on, usually 0 is used instead
    Return value: the file descriptor is returned successfully, and the file descriptor is returned failed-1
     Features: when creating a socket, the system will not allocate ports. The default attribute of the created socket is active, that is, it actively initiates service requests;As a server, it often needs to be modified to be passive 
    Header file:#include <sys/socket.h>

bind function (server specific)

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
Function: the slave function is used to bind the address to a socket.
Parameters:
	sockfd By socket The file descriptor returned by the function call.
	my_addr It's a point sockaddr Pointer to.
	addrlen yes sockaddr The length of the structure.
 Return value: failed-1

Definition of sockaddr:
When calling the programming interface function and the function needs to pass in the address structure, it needs to use struct sockaddr for forced conversion

struct sockaddr{
unisgned short  as_family;
char sa_data[14];
};

sockaddr_ Definition of in:
When defining the source address and destination address structure, select struct sockaddr_in;

struct sockaddr_in{
unsigned short   sin_family;     
unsigned short     sin_port;
struct in_addr   sin_addr;
unsigned char   sin_zero[8];
}
	Parameters:
Internet therefore sin_family Generally AF_INET. 
sin_port:Listening port number
sin_addr:Usually set to INADDR_ANY Indicates that you can communicate with any host
sin_zero[8]:Usually ignore it

listen function (exclusive to the server)

#include <sys/socket.h>
int listen(int sockfd, int backlog); 
Function: change the socket from active to passive, and enable the operating system to set a connection queue for the socket to record all connections to the socket
 Parameters:
 sockfd:  socket listening socket  
 backlog: Length of connection queue 
 Return value: 0 returned successfully, and 0 returned failed-1

accept function (exclusive to the server)

int accept(int sockfd,struct sockaddr *cliaddr, socklen_t *addrlen); 
Function: take out an established connection from the connected queue. If no connection is available, go to sleep and wait(block) 
Parameters:
sockfd:  socket listening socket 
cliaddr: Structure for storing client socket address,It is used to fill in automatically for the client program. The server only needs to pass the pointer.
addrlen: Address of socket address structure length
 Return value: connected socket
 Header file:#include <sys/socket.h> 
 Note: the returned is a connected socket, which represents the current connection

connect function (client specific)

int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
 Function: actively establish a link with the server
  Parameters:
  sockfd: socket socket 
  addr: Connected server address structure 
  len:  Address structure length 
  Return value: Success: 0 failure: other
  be careful:
  1,connect No new sockets will be generated after the connection is established 
  2,The transmission cannot start until the connection is successful TCP data 
  3,Header file:#include <sys/socket.h>

send function (available for client and server)

ssize_t send(int sockfd, const void* buf,size_t nbytes, int flags);
 Function: used to send data 
 Parameters:
 sockfd:  Socket with established connection 
 buf:  Address to send data 
 nbytes: Size of data sent(In bytes) 
 flags: Socket flag(Usually 0)
  Return value: the number of bytes successfully sent
  Header file:#Include < sys / socket. H > note: you cannot send 0-length packets with TCP protocol

recv function (available for client and server)

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd Specify the receiver socket descriptor;
Parameters:
	buf Indicates a buffer used to store recv The data received by the function;
	len to specify buf The length of the;
	flags Generally set to 0.
	Both client and server applications use recv Function from TCP The other end of the connection receives data.

Close close socket

1. Use the close function to close the socket. Closing a socket representing a connected socket will cause the other end to receive a 0-length packet
2. Closing the listening socket when working as a server will cause the server to not receive new connections, but will not affect the established connections. Closing the connected socket returned by accept will cause the connection it represents to be closed, but will not affect the listening of the server
3. Closing the connection when you are a client is closing the connection, which does not mean anything else

Port multiplexing

  1. When the connection fails or the address is occupied, port multiplexing can be set
  2. One program binds multiple tasks to the same port
  3. Bind multiple ports for one task
  4. UDP multicast can also set port multiplexing
//Set port multiplexing
int yes=1;
setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR,&yes, sizeof(yes));
//Set socket support broadcast
int yes=1;
setsockopt(sockfd, SOL_SOCKET,SO_BROADCAST,&yes, sizeof(yes));
//Set up multicast
setsockopt(sockfd, IPPROTO_IP,IP_ADD_MEMBERSHIP, &merq, sizeof(merq));

Preparation of TCP simple client

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <pthread.h>

int main(int argc,char **argv)
{
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr;
    pthread_t pth;

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    socklen_t addrlen = sizeof(server_addr);
    inet_pton(AF_INET, "10.36.145.33", &server_addr.sin_addr.s_addr);
    int err = connect(sock_fd, (struct sockaddr *)&server_addr, addrlen);
    // printf("%u\n", INADDR_ANY);
    //    char ip[48];
    // //
    // // send(sock_fd, ip, strlen(ip), 0);
    //   inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, ip, 16);
    //         printf("%s\n", ip);
      if (err != 0)
      {
          perror("socket");
      }

        while (1)
        {
            char buf[63];
            fgets(buf, sizeof(63), stdin);
            send(sock_fd, buf, strlen(buf), 0);
        }
     }
     

Preparation of TCP simple server (can only communicate with one client at the same time)

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <pthread.h>

#if 1
/*
Function: you can only communicate with one client at the same time. Unless the client exits or sends a bye instruction, you can connect to the next client
*/
#define client_max 10
 struct sockaddr_in cli_addr;
 int sock_fd;
 int sockfd_new;
 int state = 1;
 struct sockaddr_in my_addr;
 socklen_t addrlen;
int main()
{
    // 1. Create socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in my_addr;
    pthread_t pth;

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(6666);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addrlen = sizeof(my_addr);

    //2. Server binding
   int err=bind(sock_fd, (struct sockaddr *)&my_addr, addrlen);
    if(err == -1)
    {
        perror("socket");
    }

    //3. Monitor sockets from active to passive
    err = listen(sock_fd, client_max);
    if(err == -1)
    {
        perror("socket");
    }
    printf("success\n");

    while (1)
    {
    
        char ip[16] = "";
        if(state==1)
        {        
       // bzero(&cli_addr, addrlen);
         //4. Wait for the client to connect, otherwise it will be blocked
        sockfd_new = accept(sock_fd, (struct sockaddr *)&cli_addr, &addrlen);
                inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, ip, addrlen);
               printf("%d:%s Connected\n", sockfd_new, ip); 
       }

            state = 2;          
            char buf[64]="";
            recv(sockfd_new, buf, sizeof(buf), 0);
            printf("%d\n", sockfd_new);
            if(strncmp(buf,"bye",3)== 0||strlen(buf)== 0)
            {
                printf("The other party has been closed\n");
                state = 1;
                break;
            }
    }
    return 0;
}
#endif

TCP triple handshake


1. Source port number: sender port number

2. Destination port number: receiver port number

3. Serial number: the serial number of the first byte of the data in this report section

4. Confirmation sequence number: the sequence number of the first data byte expected to receive the other party's next message segment

5. Header length (data offset): how far is the data start of TCP message segment from the start of TCP message segment, i.e. header length. Unit: 32 bits, i.e. 4 bytes.

6. Reserved: 6 digits, reserved for future use, and should be set to 0 at present

7. Emergency URG: this position 1 indicates that the emergency pointer field is valid. It tells the system that there is emergency data in this message segment and should be transmitted as soon as possible

8. Confirm ACK: the confirmation number field is valid only when ACK=1. TCP stipulates that all transmitted message segments must set ACK to 1 after the connection is established

9. Push PSH: when two application processes communicate interactively, sometimes the application process at one end wants to receive the other's response immediately after typing a command. In this case, TCP can use the push operation. At this time, the sender TCP sets PSH to 1 and immediately creates a message segment to send. After receiving the message segment with PSH=1, the receiver will deliver it to the receiving application process as soon as possible (i.e. "push" forward), instead of waiting until the whole cache is filled

10. Reset RST: used to reset the corresponding TCP connection

11. Synchronous SYN: valid only when TCP connection is established through three handshakes. When SYN=1 and ACK=0, it indicates that this is a connection request message segment. If the other party agrees to establish a connection, SYN=1 and ACK=1 shall be used in the corresponding message segment. Therefore, setting SYN to 1 indicates that this is a connection request or connection acceptance message

12. Terminate FIN: used to release a connection. When FIN=1, it indicates that the data of the sender of this message segment has been sent, and it is required to release the transport connection.

13. Window: refers to the receiving window of the party sending this report segment (rather than its own sending window)

14. Checksum: the scope of checksum field inspection includes header and data. 12 byte pseudo header needs to be added when calculating checksum

15. Emergency pointer: it is meaningful only when URG=1. It indicates the number of bytes of emergency data in this report segment (ordinary data after the end of emergency data), that is, it indicates the position of the end of emergency data in the message. Note: emergency data can be sent even when the window is zero

16. Option: variable length, up to 40 bytes. When the option is not used, the TCP header length is 20 bytes

First connection: when the client calls the connect function, the client sends a SYN package to the server: serial number = 0, confirmation serial number = 0

Second connection: when the server receives the syn package, it sends the syn to the client for the first time: the serial number is 0, and the confirmation serial number is 1

The third connection: the client indicates that it has received and sent an ack to the server: serial number 0, confirmation serial number = 1

TCP waved four times

Let's review the TCP header:

Condition for four waves: call the close function

We can know from the picture:
First wave: serial number = m confirmation number = m+1

The second wave: serial number = m+1, confirmation number = m+1. At this time, an ACK is returned as 1

The third wave: serial number = m+1, confirmation number = m+1, send a FIN message again

The fourth wave: serial number = m+1, confirmation number = m+2, and finally send an ACK response message


Summary: suppose that the client is disconnected, send a FIN first, and the server replies with an ACK response. After sending the response, send a FIN again, and finally the client sends an ACK to confirm the disconnection.

Question: why can't disconnect and ack be sent in one packet
A: only by calling the close function will the disconnect packet be sent, but the ack will reply as long as it receives the other party's disconnect packet. There is a time difference between ack and fin. Therefore, it is not allowed to send ack and fin at the same time, and one end will send them to the other end twice in a row

Problem: it is the client that actively disconnects. After receiving the ack sent by the server, it can still receive data.

A: because it hasn't finished waving, the client is half closed and can receive data.

Preparation of high concurrency server (process version)

Concept: in the past, we wrote that a server can only connect one client at the same time. A highly concurrent server can connect multiple clients and communicate at the same time.

#if 1
/*
Function: one server communicates with multiple clients at the same time (using process method)
*/
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <pthread.h>

#define client_max 10
struct sockaddr_in cli_addr;

int sock_fd;
int sockfd_new;
int state = 1;
int pid;
struct sockaddr_in my_addr;
socklen_t addrlen;

void *pthread (void *arg)
{

}
int main()
{
    // 1. Create socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in my_addr;
    pthread_t pth;

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(6666);//This port should be the same as the client port
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addrlen = sizeof(my_addr);
    //Set port multiplexing
    int yes = 1;
    setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    //2. Server binding
    int err = bind(sock_fd, (struct sockaddr *)&my_addr, addrlen);
    if (err == -1)
    {
        perror("socket");
    }

    //3. Monitor sockets from active to passive
    err = listen(sock_fd, client_max);
    if (err == -1)
    {
        perror("socket");
    }
    printf("success\n");

    while (1)
    {
        // bzero(&cli_addr, addrlen);
        //4. Wait for the client to connect, otherwise it will be blocked
        sockfd_new = accept(sock_fd, (struct sockaddr *)&cli_addr, &addrlen);
        pid = fork();
        if (pid < 0)
        {
            printf("fork error\n");
        }
        else if (pid == 0)
        {
            close(sock_fd);//This socket is not used
            char ip[16] = "";
            inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, ip, addrlen);
            printf("Connected%s\n", ip);
            while (1)
            {
                char buf[64] = "";
                recv(sockfd_new, buf, sizeof(buf), 0);
                printf("%d\n", sockfd_new);
                if (strncmp(buf, "bye", 3) == 0 || strlen(buf) == 0)
                {
                    printf("The other party has been closed\n");
                    close(sockfd_new);
                    break;
                }
            }
            exit(1);
        }
        else if (pid > 0)
        {
              close(sockfd_new);//This is not required by the parent process, but only within the child process
        }
    }
    return 0;
}
#endif 

Preparation of high concurrency server (threaded version)

Concept: in the past, we wrote that a server can only connect one client at the same time. A highly concurrent server can connect multiple clients and communicate at the same time.

#if 1
/*
Function: one server communicates with multiple clients at the same time (using thread method)
*/
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <pthread.h>

#define client_max 10


int sock_fd;

int pid;

typedef struct 
{
  int sockfd_new;
  char ip[16];
  struct sockaddr_in cli_addr;
} Myadd;

struct sockaddr_in my_addr;
socklen_t addrlen;

void *pthread (void *arg)
{
        Myadd p = *(Myadd *)arg;
       inet_ntop(AF_INET, &p.cli_addr.sin_addr.s_addr, p.ip, 16);
       printf("%d,%s Connected\n",p.sockfd_new, p.ip);
       while (1)
       {

           printf("%p\n", &p);
           char buf[64] = "";
           recv(p.sockfd_new, buf, sizeof(buf), 0);
           printf("%d,%s", p.sockfd_new, buf);

           if (strncmp(buf, "bye", 3) == 0 || strlen(buf) == 0)
           {
               printf("The other party has been closed\n");
               close(p.sockfd_new);
               break;
           }
         }
    
}
int main()
{
    // 1. Create socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in my_addr;
    pthread_t pth;

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(6666);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addrlen = sizeof(my_addr);
    //Set port multiplexing
    int yes = 1;
    setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    //2. Server binding
    int err = bind(sock_fd, (struct sockaddr *)&my_addr, addrlen);
    if (err == -1)
    {
        perror("socket");
    }

    //3. Monitor sockets from active to passive
    err = listen(sock_fd, client_max);
    if (err == -1)
    {
        perror("socket");
    }
    printf("success\n");

    while (1)
    {
        Myadd add;
 
         bzero(&add.cli_addr, addrlen);
        //4. Wait for the client to connect, otherwise it will be blocked
        add.sockfd_new = accept(sock_fd, (struct sockaddr *)&add.cli_addr, &addrlen);
        pthread_create(&pth, NULL, pthread, (void*)&add);//Create thread
        pthread_detach(pth);	
        usleep(1000);
    }
    return 0;
}
#endif 

Tags: Linux socket udp TCP/IP

Posted on Sun, 26 Sep 2021 07:32:22 -0400 by BANDYCANDY