Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

1 UDP network programming

1.1 process

Server:

  1. Create socket socket()
  2. Fill in the server network information struct sockaddr_in
  3. Bind () bind the socket to the server network information structure
  4. Communicate recvfrom()/sendto()

Client:

  1. Create socket socket()
  2. Fill in the server network information struct sockaddr_in
  3. Communicate recvfrom()/sendto()

1.2 recvfrom ()/sendto ()

1 — recvfrom()

  1. The header file:
    1. #include <sys/types.h>
    2. #include <sys/socket.h>
  2. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  3. Function: Receives data
  4. Parameters:
    1. Sockfd: indicates the file descriptor

      1. Server: Return value of Accept
      2. Client: return value of the socket
    2. Buf: saves the received data

    3. Len: The number of bytes to receive theoretically

    4. Flags: indicates the flag bit

      1. 0 block

      2. The MSG_DONTWAIT non-blocking

    5. Src_addr: the address of the source, whose data is received, and whose information is automatically populated with this parameter

    6. Addrlen: indicates the size of src_ADDR

  5. The return value:
    1. Success: Number of bytes actually received
    2. Failure: 1

2 — sendto()

  1. The header file:
    1. #include <sys/types.h>
    2. #include <sys/socket.h>
  2. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  3. Function: Send data
  4. Parameters:
    1. Sockfd: indicates the file descriptor

      1. Server: Return value of Accept
      2. Client: return value of the socket
    2. Buf: data to be sent

    3. Len: The theoretical number of bytes to send

    4. Flags: indicates the flag bit

      1. 0 block

      2. The MSG_DONTWAIT non-blocking

    5. Dest_addr: specifies the destination address

    6. Addrlen: specifies the size of dest_addr

  5. The return value:
    1. Success: number of bytes sent
    2. Failure: 1

1.3 Code (two demos)

1.3.1 server

//UDP network programming server

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h> 
#include <string.h>

#define N 128
#defineERRLOG(errmsg) do{\ perror(errmsg); \ printf("%s - %s - %d\n", __FILE__, __func__, __LINE__); \ exit(1); \ }while(0)

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr."Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd;
    struct sockaddr_in serveraddr.clientaddr;
    socklen_t addrlen = sizeof(serveraddr);
    char buf[N] = {0};

    // Step 1: Create a socket
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) = =- 1)
    {
        ERRLOG("socket error");
    }

    // Step 2: Populate the server network information structure
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    // Step 3: bind the socket to the server network information structure
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) == - 1)
    {
        ERRLOG("bind error");
    }

    // Communicate
    while(1)
    {
NEXT:
        if(recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, &addrlen) == - 1)
        {
            ERRLOG("recvfrom error");
        }

        if(strcmp(buf, "quit") = =0)
        {
            printf("Client %s-%d exited \n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
            goto NEXT;
        }

        printf("% s % d: % s \ n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buf);
    
        strcat(buf, "^_^");

        if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, addrlen) == - 1)
        {
            ERRLOG("sendto error"); }}return 0;
}
Copy the code

1.3.2 the client

//UDP network programming client

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h> 
#include <string.h>

#define N 128
#defineERRLOG(errmsg) do{\ perror(errmsg); \ printf("%s - %s - %d\n", __FILE__, __func__, __LINE__); \ exit(1); \ }while(0)

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr."Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);

    // Step 1: Create a socket
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) = =- 1)
    {
        ERRLOG("socket error");
    }

    // Step 2: Populate the server network information structure
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    // Communicate
    char buf[N] = {0};
    while(1)
    {
        fgets(buf, N, stdin);
        buf[strlen(buf) - 1] = '\ 0';

        if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, addrlen) == - 1)
        {
            ERRLOG("sendto error");
        }

        if(strcmp(buf, "quit") = =0)
        {
            printf("Client exits \n");
            exit(0);
        }

        memset(buf, 0, N);

        if(recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, &addrlen) == - 1)
        {
            ERRLOG("recvfrom error");
        }

        printf("Server: %s\n", buf);
    }

    return 0;
}
Copy the code

2 TFTP protocol based on UDP

2.1 Basic Concepts

TFTP: == Simple file transfer protocol ==

Originally used to boot diskless systems, it was designed to transfer small files

Features:

  1. Based on UDP protocol implementation
  2. User validity authentication is not performed

Data transmission mode:

  1. Octet: indicates the binary mode
  2. Netascii: text mode
  3. Mail: No longer supported

2.2 Client File Download Communication Process

First of all, the client will send a message to the server to inform the service that I want to download. The first message sent is the request instruction. Note that the fixed == port number is 69==.

The server returns a packet to the client, [numbered, size, and content (512) (default)]

After receiving the data packet, the client receives the data packet and writes the contents of 512 files to the specified file. After receiving the data, the client sends a reply packet to the server. The serial number is the same as that of the received data packet.

Then the correspondence continued;

Until less than 512 packets have been sent,

Summary of TFTP Communication Process (no option)

  1. The server is waiting for a client request on port 69
  2. If the server approves the request, it communicates with the client using a temporary port
  3. The number of each packet changes (starting from 1)
  4. Each packet is acknowledged by an ACK, and if a timeout occurs, the last packet (data or ACK) needs to be resent
  5. Data is transmitted in 512 bytes
  6. Data smaller than 512 bytes indicates the end of transmission

2.3 Protocol Analysis

Note that the client downloads the file read, and the server uses the opcode to distinguish between requests

Read/write request: For example, if the operation code is 1, download + file name +0 interval + mode (eg: OCTET) +0 indicates the end.

Error code:

  • 0 is not defined. See Error message
  • 1 File not found.
  • 2 Access violation.
  • 3 Disk full or allocation exceeded.
  • 4 illegal TFTP operation.
  • 5 Unknown transfer ID.
  • 6 File already exists.
  • 7 No such user.
  • 8 Unsupported option(s) requested.

2.4 Downloading function Package and Receiving Data and Parsing by TFTP Client (Demo)

Maximum download 32M, 65535*

//UDP network programming client

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h> 
#include <string.h>

#define N 128
#defineERRLOG(errmsg) do{\ perror(errmsg); \ printf("%s - %s - %d\n", __FILE__, __func__, __LINE__); \ exit(1); \ }while(0)

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr."Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);

    // Step 1: Create a socket
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) = =- 1)
    {
        ERRLOG("socket error");
    }

    // Step 2: Populate the server network information structure
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    char filename[32] = {0};
    printf("Please enter the file name to download:");
    scanf("%s", filename);

    // The TFTP client implements the download function
    // The package sends the data to the server and tells it to download
    // If you define a structure, the filename is indeterminate
    unsigned char buf[600] = {0};/ / packet
    int n;// The number of bytes in the packet
    unsigned short code;/ / sent wrong words.if
    unsigned short num;/ / block number
    unsigned char text[600] = {0};// Store the content
    ssize_t bytes;// The number of bytes to receive, up to 516
    
    // Opcode assignment
    // Method 1: cast two bytes of space and assign the value of the network byte order
    //*(unsigned short *)buf = htons(1);
    
    // Method 2: Split the data into one byte units, so you don't need to worry about byte order
    //buf[0] = 0;
    //buf[1] = 1;

    / / set package:
    n = sprintf(buf, "%c%c%s%c%s%c".0.1, filename, 0."octet".0);
    // Send data to the server
    if(sendto(sockfd, buf, n, 0, (struct sockaddr *)&serveraddr, addrlen) == - 1)
    {
        ERRLOG("sendto error");
    }

    // Receive data
    memset(buf, 0.600);
    if((bytes = recvfrom(sockfd, buf, 600.0, (struct sockaddr *)&serveraddr, &addrlen)) == - 1)
    {
        ERRLOG("recvfrom error");
    }

    // Parse the packet
    //buf is the entire data, which is then parsed in segments
    / / operation code
    code = ntohs(*(unsigned short *)buf);
    // Block number or error code
    num = ntohs(*(unsigned short *)(buf+2));
    // File contents or error information
    strncpy(text, buf+4, bytes4 -);// Intercepts 512 packets

    printf("code:%d, num:%d\n", code, num);
    printf("%s\n", text);

    return 0;
}
Copy the code