Various Options for Learning Note Sockets in TCP/IP Network Programming

Keywords: socket network Programming

1. Options for sockets

  • After creating sockets, you can modify socket features
  • Socket options are divided into three layers: SOL_SOCKET, IPPROTO_IP and IPPROTO_TCP.

2. Relevance function

  • getsockopt
#include<sys/socket.h>
// Function: Get information about socket options
// Parameters:
//    sock -- Used to view options socket file descriptors
//    level -- Optional protocol layer to view
//    optname -- Optional name to view
//    optval -- Save the buffer address value of the result to view
//    optlen -- The buffer size passed to the fourth parameter optval. After calling the function, the number of bytes in the variable that hold the optional information returned by the fourth parameter
// Return value: Return 0 on success and - 1 on failure
int getsockopt(int sock, int level,int optname, void* optval, socklen_t* optlen);
  • setsockopt
#include<sys/socket.h>
// Function: Setting socket options
// Parameters:
//    sock -- Socket file descriptor for changing optional options
//    level -- Optional protocol layer to be changed
//    optname -- an optional name to change
//    Optival -- Buffer address value that holds the option information to be changed
//    optlen -- The number of bytes of optional information passed to the fourth parameter optval
// Return value: Return 0 on success and - 1 on failure
int setsockopt(int sock, int level, int optname, const void* optval, socklen_t optlen);

3. Get sock_type

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

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

int main(int argc, char* argv[]) {
    int tcp_sock, udp_sock;
    int sock_type;

    socklen_t optlen = sizeof(sock_type);
    tcp_sock = socket(PF_INET, SOCK_STREAM, 0);
    udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
    printf("SOCK_STREAM: %d \n", SOCK_STREAM);
    printf("SOCK_DGRAM: %d \n", SOCK_DGRAM);

    int state = getsockopt(tcp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);
    if (state)
        error_handling("getsockopt() error!");
    printf("Socket type one: %d \n", sock_type);

    state = getsockopt(udp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);
    if (state)
        error_handling("getsockopt() error!");
    printf("Socket type two: %d \n", sock_type);

    return 0;
}

Running results: sock_type can only be obtained, not set; socket type can only be specified at the time of creation, can not be modified.

4. Get and modify socket buffer size

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

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

int main(int argc, char* argv[]) {
    int sock;
    int snd_buf, rcv_buf;

    sock = socket(PF_INET, SOCK_STREAM, 0);

    socklen_t len = sizeof(snd_buf);
    int state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
    if (state)
        error_handling("getsockopt() error");

    len = sizeof(rcv_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
    if (state)
        error_handling("getsockopt() error");

    printf("Default input buffer size: %d \n", rcv_buf);
    printf("Default output buffer size: %d \n", snd_buf);

    snd_buf = 1024 * 3;
    rcv_buf = 1024 * 3;

    state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, sizeof(rcv_buf));
    if (state)
        error_handling("setsockopt() error");

    state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, sizeof(snd_buf));
    if (state)
        error_handling("setsockopt() error");

    len = sizeof(snd_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
    if (state)
        error_handling("getsockopt() error");

    len = sizeof(rcv_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
    if (state)
        error_handling("getsockopt() error");

    printf("After setting, input buffer size: %d \n", rcv_buf);
    printf("After setting, output buffer size: %d \n", snd_buf);

    return 0;
}

Running results: The size of IO buffer set is not consistent with the specified 3K. This is automatically adjusted by the system.

5.Time-wait state

  • In communication, the client first requests to disconnect the link, sends FIN to the server and then goes through four "wave" processes, and then enters the time-wait state. Enter ctrl+c to force the termination of the program. At this time, the operating system closes the file and socket, which is equivalent to calling the close function, and also sends FIN.
  • If the server terminates the program compulsively in the process of communication and runs the server-side program with the same port again immediately, it will enter "bind() error" and cannot run again. Wait a few minutes to run again.
  • Reason analysis: First disconnected (FIN sent first) host will go through the Time-wait state, at this time the corresponding port is still in use, call bind() using the same port will make mistakes.
  • The port number of the client socket is automatically assigned, so there is no need to consider the Time-wait state of the client.
  • Why is there a Time-wait state? Assuming that host A cancels the socket immediately after sending the last ACK packet, but this ACK message is lost in the transmission process and cannot be transmitted to host B, host B will think that the message it sent before did not reach host A and try to retransmit, but at this time A has completely terminated and can not receive the final ACK from host B. With Time-wait status, Host A retransmits the final ACK message like Host B, and Host B can terminate normally.
  • Following is the echo server/client communication process, you can find that the server-side forced termination of the program, immediately run again, will report errors.

6. Port number redistribution in Time-wait state, modifying SO_REUSEADDR option

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

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

int main(int argc, char* argv[]) {
    int serv_sock, clnt_sock;
    struct sockaddr_in serv_addr, clnt_addr;
    char message[30];

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

    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (serv_sock == -1)
        error_handling("socket() error");

    int option = 1;
    socklen_t optlen = sizeof(option);
    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen);

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

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

    if (listen(serv_sock, 5) == -1)
        error_handling("listen() error");

    socklen_t clnt_addr_size = sizeof(clnt_addr);
    clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    if (clnt_sock == -1)
        error_handling("accept() error");

    int str_len;
    // After receiving the client's message, send it back to the client
    while ((str_len = read(clnt_sock, message, sizeof(message))) != 0) {
        write(clnt_sock, message, str_len);
        write(1, message, str_len);
    }

    close(clnt_sock);
    close(serv_sock);
    return 0;
}

Running results: It can be seen that even if the server end of the program forcibly, immediately re-execute the program, no error.

7.Naggle algorithm

  • By default, TCP uses Naggle algorithm to exchange data, so it buffers as much as possible until it receives ACK.
  • It is better to disable Naggle algorithm when transferring large file data in order to improve transmission speed.
  • Naggle algorithm can be disabled simply by changing TCP_NODELAY to 1

Reference Books: TCP/IP Network Programming Yin Shengyu, Translated by Jin Guozhe

Posted by RichterBelmont on Sat, 11 May 2019 16:55:39 -0700