Socket: datagram socket

1. What is a datagram socket

  • A socket, or socket, is a communication mechanism by which a client/server (that is, a process to communicate)The system can be developed either locally on a single machine or across a network. That is, it allows processes that are not on the same machine but are connected over a network to communicate. Because of this, sockets clearly distinguish between clients and servers.

  • Compared to stream sockets, datagram sockets are easier to use. They are specified by the type SOCK_DGRAM and do not require a connection to be established or maintained. They are usually implemented in AF_INET through the UDP/IP protocol. They limit the length of data that can be sent and the datagram is transmitted as a single network message.UDP is not a reliable protocol, but it is faster because it always needs to establish and maintain a connection.

2. Workflow of client/server based on stream socket

1. Server

  • As with stream sockets, first the server application creates a socket with a system call to socket(), which is a similar file descriptor resource that the system assigns to the server process and cannot be shared with other processes.

  • Next, the server process names the socket (listening), and we use the system call bind() to name the socket. Then the server process waits for the client to connect to the socket.

  • The difference is that the system then calls recvfrom() to receive the data sent from the client program. The server program processes the data accordingly, and then sends the processed data back to the client program through a system call sendto().

Compared to Stream Sockets:

  • In a program on a stream socket, data is received through a system call read, and data is sent through a system call write(), whereas in a datagram socket program, it is achieved through recvfrom() and sendto() calls.
    Server programs that use datagram sockets do not require listen() calls to create a queue to store connections, nor accept() calls to receive connections and create a new socket descriptor

2. Client

  • Clients based on datagram sockets are simpler than servers. Similarly, client applications call sockets first to create an unnamed socket. Just like servers, clients send data to servers and receive data from server programs through sendto() and recvfrom().

Compared to Stream Sockets:

  • Clients using datagram sockets do not need to use the connect() system call to connect to the server program; they only need to send information to the IP port that the server is listening for and receive data sent back from the server when needed.

3. Socket Interface

  • Universal Socket Interface See another blog: Streaming Sockets

1. recvfrom() system call

  • This function stores the information sent to the program in a buffer buffer and records the program IP port of the data source. This function is blocked
int recvfrom(int sockfd, void *buffer, size_t len,int flags, struct sockaddr *src_from, socklen_t *src_len); 
  • The buffer stores the received data, len specifies the length of the buffer, and flags are usually set to 0 in applications. If src_front is not empty, the IP port of the data source program is recorded. If src_len is not empty, the length information is recorded in the variable that src_len points to.

2. sendto() system call

  • This function sends information from the buffer buffer buffer to the program on the specified IP port
int sendto(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *to, socklen_t tolen);
  • Buffer stores the data to be sent, len is the length of the buffer, flags in applications are usually set to 0, to is the IP port of the program to which the data is to be sent, and to len is the length of the to parameter. The number of bytes of data to be sent is returned on success and -1 on failure.

4. Examples

server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
 
int main(int arc, char **argv)
{
    int server_sockfd = -1;
    socklen_t server_len = 0;
    socklen_t client_len = 0;
    char buffer[512];
    ssize_t result = 0;
 
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
 
    // Create Datagram Socket
    server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 
    // Set the port, IP to listen on
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(9739);
    server_len = sizeof(server_addr);
 
    // Bind (named) socket
    bind(server_sockfd, (struct sockaddr *)&server_addr, server_len);
 
    // Ignore information about the child process stopping or exiting, and the child process will be managed by the kernel when it becomes a zombie process
    signal(SIGCHLD, SIG_IGN);
 
    while (1)
    {
        // Receive data and use client_addr to store the IP port of the data source program
        // Functions block the ability to know when data is received from the client
        result = recvfrom(server_sockfd, buffer, sizeof(buffer), 0,
                          (struct sockaddr *)&client_addr, &client_len);
        if (fork() == 0)
        {
            // Using subprocesses to process data
            buffer[0] += 'a' - 'A';
 
            // Send processed data
            sendto(server_sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, client_len);
 
            printf("%c\n", buffer[0]);
 
            // Note that you must close the subprocess or the program will not work properly
            exit(0);
        }
    }
 
    // Close
    close(server_sockfd);
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
#include <netinet/in.h>
#include <arpa/inet.h>
 
int main(int argc, char **argv)
{
    struct sockaddr_in server_addr;
    socklen_t server_len = 0;
    int sockfd = -1;
    char c = 'A';
 
    // Take the first character of the first parameter
    if (argc > 1)
    {
        c = argv[1][0];
    }
 
    // Create Datagram Socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 
    // Set Server IP, Port
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(9739);
    server_len = sizeof(server_addr);
 
    // Send data to server
    sendto(sockfd, &c, sizeof(char), 0,
           (struct sockaddr *)&server_addr, server_len);
 
    // The last two parameters are set to 0 because the data source is not concerned when the receiving server processes the sent data.
    recvfrom(sockfd, &c, sizeof(char), 0, 0, 0);
 
    printf("char from server = %c\n", c);
 
    // Close
    close(sockfd);
    exit(0);
}

Tags: Linux udp

Posted on Tue, 12 Oct 2021 14:01:27 -0400 by MarineX69