"TCP/IP Network Programming" reading notes -- UDP-based server/client

Table of contents

1--The main difference between TCP and UDP

2-- UDP-based data I/O function

3-- UDP based echo server/client

4--Address assignment of UDP client Socket

5--UDP has a data boundary

6--UDP connected and not connected settings


1--The main difference between TCP and UDP

① TCP provides reliable data transmission services, while UDP provides unreliable data transmission services;

② UDP is more concise in structure than TCP, it will not send ACK response message, nor will it assign sequence numbers similar to SEQ to data packets;

③ Flow control is the most important sign to distinguish UDP and TCP, UDP is faster than TCP;

④ There are two main reasons why TCP is slower than UCP: one is that TCP needs to perform connection setup and clearing processes before and after sending and receiving data; the other is the flow control added by TCP to ensure reliability during sending and receiving data;

⑤ TCP Socket is a one-to-one relationship, so when it is necessary to provide services for multiple clients, multiple TCP Sockets need to be created, while UDP only needs one Socket on both the server side and the client side;

2-- UDP-based data I/O function

#include <sys/socket.h>
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen); 
// 成功时返回传输的字节数,失败时返回 -1
// sock 表示传输数据的 UDP Socket 的文件描述符
// buff 表示保存待传输数据的缓冲地址值
// nbytes 表示待传输的数据长度,以字节为长度
// flags 可选项参数,若没有则传递 0
// to 存有目标地址信息的 sockaddr 结构体变量的地址值
// addrlen 传递给参数 to 的地址值结构体变量长度
#include <sys/socket.h>
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t *addrlen);

// 成功时返回接收的字节数,失败时返回 -1
// sock 表示用于接收数据的 UDP socket的文件描述符
// nbytes 保存接收数据的缓冲地址值
// flags 可选项参数,若没有则传入 0
// from 存有发送端地址信息的 sockaddr 结构体变量的地址值
// addrlen 保存参数 from 的结构体变量长度的变量地址值

3-- UDP based echo server/client

Service-Terminal:

// gcc uecho_server.c -o uecho_server
// ./uecho_server 9190

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]){
    int serv_sock;
    char message[BUF_SIZE];
    int str_len;
    socklen_t clnt_adr_sz;
    struct sockaddr_in serv_adr, clnt_adr;

    if(argc != 2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    if(serv_sock == -1){
        error_handling("UDP socket creation error");
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));

    if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){
        error_handling("bind() error");
    }

    while(1){
        clnt_adr_sz = sizeof(clnt_adr);
        str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
        sendto(serv_sock, message, str_len, 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
    }
    close(serv_sock);
    return 0;
}

client:

// gcc uecho_client.c -o uecho_client
// ./uecho_client 127.0.0.1 9190

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]){
    int sock;
    char message[BUF_SIZE];
    int str_len;
    socklen_t adr_sz;
    struct sockaddr_in serv_adr, from_adr;

    if(argc != 3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if(sock == -1){
        error_handling("socket() error");
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));

    while(1){
        fputs("Insert message(q to quit): ", stdout);
        fgets(message, sizeof(message), stdin);

        if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")){
            break;
        }

        sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
        adr_sz = sizeof(from_adr);
        str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&from_adr, &adr_sz);
        message[str_len] = 0;
        printf("Message from server: %s", message);
    }
    close(sock);
    return 0;
}

operation result:

4--Address assignment of UDP client Socket

        The TCP client calls the connect() function to automatically complete the allocation of IP and port;

        The UDP client calls the sento() function to automatically complete the allocation of IP and port;

5--UDP has a data boundary

        There is no data boundary in TCP data transmission, but there is a data boundary in UDP data transmission, so the number of calls of the input function (recvfrom) and output function (sendto) should be the same;

6--UDP connected and not connected settings

        The UDP Socket is unconnected by default, so every time data is transmitted, the destination address (IP, Port) needs to be carried, which is an unconnected Socket;

        Similar to TCP Socket, UDP can also call the connect() function to set the target address, thereby creating a connected UDP Socket;

        The connected UDP Socket can not only use the sendto and recvfrom functions, but also use the write and read functions to communicate because the sending and receiving objects are specified;

        The echo client based on connected UDP is as follows:

// gcc uecho_con_client.c -o uecho_con_client
// ./uecho_con_client 127.0.0.1 9190

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]){
    int sock;
    char message[BUF_SIZE];
    int str_len;
    socklen_t adr_sz;
    struct sockaddr_in serv_adr, from_adr;

    if(argc != 3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if(sock == -1){
        error_handling("socket() error");
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));

    connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr));

    while(1){
        fputs("Insert message(q to quit): ", stdout);
        fgets(message, sizeof(message), stdin);

        if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")){
            break;
        }

        write(sock, message, strlen(message));
        str_len = read(sock, message, sizeof(message) - 1);
        message[str_len] = 0;
        printf("Message from server: %s", message);
    }
    close(sock);
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43863869/article/details/132716765