Understanding of multiple options of socket

Multiple options for sockets

Specific source code can refer to my GitHub

1. Socket options and I/O buffer size

When we do socket programming, we usually only focus on data communication and ignore the different characteristics of sockets. However, it is also important to understand these features and make changes as needed

1.1 multiple options for sockets

Options are layered.

protocol layer Option name read Set up
SOL_SOCKET SO_SNDBUF O O
SOL_SOCKET SO_RCVBUF O O
SOL_SOCKET SO_REUSEADDR O O
SOL_SOCKET SO_KEEPALIVE O O
SOL_SOCKET SO_BROADCAST O O
SOL_SOCKET SO_DONTROUTE O O
SOL_SOCKET SO_OOBINLINE O O
SOL_SOCKET SO_ERROR O X
SOL_SOCKET SO_TYPE O X
IPPROTO_IP IP_TOS O O
IPPROTO_IP IP_TTL O O
IPPROTO_IP IP_MULTICAST_TTL O O
IPPROTO_IP IP_MULTICAST_LOOP O O
IPPROTO_IP IP_MULTICAST_IF O O
IPPROTO_TCP TCP_KEEPALIVE O O
IPPROTO_TCP TCP_NODELAY O O
IPPROTO_TCP TCP_MAXSEG O O

Generally, there are three types of protocol layers

Sol? Socket layer: it is a general option related to socket

IP proto? IP layer: IP protocol related matters

Ipproto? TCP layer: matters related to TCP protocol

1.2 common operations

There are two operations: Get read and Set.

Read function

#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
Success returned 0, failure returned - 1
    Socket descriptor
    Level > protocol layer to view
    Optname -- > optional item name
    Optval -- > save the buffer address value of the view result
    Optlen -- > buffer size passed to the fourth parameter optval

Setting function

#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
Success 0 failed - 1
    optval saves the option information buffer address value to be modified
    Number of bytes of optlen passing optional information
    Other ibid

An example of calling the getsockopt function is as follows:

  • [sokc_type]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

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

int main() {
    int TCP_sock, UDP_sock;
    int sock_type;
    socklen_t optlen;
    int state;
    TCP_sock = socket(PF_INET, SOCK_STREAM, 0);
    UDP_sock = socket(PF_INET, SOCK_DGRAM, 0);
    printf("SOCK_STREAM: %d\n SOCK_DGRAM: %d\n", SOCK_STREAM, SOCK_DGRAM);
    printf("PF_INET: %d\n", PF_INET);
    state = getsockopt(TCP_sock, SOL_SOCKET, SO_TYPE, (void*) &sock_type, &optlen);
    if (state)
        error("getsockopt() error");
    printf("TCP_sock type : %d \n optlen: %d\n", sock_type, optlen);
    state = getsockopt(UDP_sock, SOL_SOCKET, SO_TYPE, (void*) &sock_type, &optlen);
    if (state)
        error("getsockopt() error");
    printf("UDP_sock type : %d \n optlen: %d\n", sock_type, optlen);
    close(TCP_sock);
    close(UDP_sock);
    return 0;
}
  • Note: sometimes there will be errors when running. Just run it several times more.
  • Socket type can only be determined after creation, and cannot be changed later.

Compile run:

gcc sock_type.c -o sock_type
./sock_type

Operation result:

SOCK_STREAM: 1
 SOCK_DGRAM: 2
PF_INET: 2
TCP_sock type : 1 
 optlen: 4
UDP_sock type : 2 
 optlen: 4
1.3 I/O buffer size

I/O buffer will be generated at the same time when socket is generated.

So? Rcvbuf is the optional input buffer size, so? Sndbuf is the optional output buffer size

Read and change cases

read

  • [get_buf.c]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
void error(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
int main() {
    int sock;
    int snd_buf, rcv_buf, state;
    socklen_t len;
    sock = socket(PF_INET, SOCK_STREAM, 0);
    len = sizeof(snd_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
    if (state)
        error("getsockopt() error");
    len = sizeof(rcv_buf);
    state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
    if (state)
        error("getsockopt() error");
    printf("INPUT buffer: %d\n", rcv_buf);
    printf("OUTput buffer: %d\n", snd_buf);
    close(sock);
    return 0;
}

Compile run:

gcc get_buf.c -o get_buf
./get_buf

Operation result:

INPUT buffer: 131072
OUTPUT buffer: 16384

This is my I / O buffer size

change

  • [set_buf.c]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
void error(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char* argv[]) {
    int sock, state;
    int snd_buf = 1024*3;
    int rcv_buf = 1024*3;
    socklen_t len;
    sock = socket(PF_INET, SOCK_STREAM, 0);
    len = sizeof(rcv_buf);
    state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcv_buf, sizeof(rcv_buf));
    if (state)
        error("setsockopt() 1 error");
    len = sizeof(snd_buf);
    state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&snd_buf, sizeof(snd_buf));
    if (state)
        error("setsockopt() 2 error");
    state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcv_buf, &len);
    if (state)
        error("getsockopt() 1 error");
    state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&snd_buf, &len);
    if (state)
        error("getsockopt() 2 error");
    printf("INPUT :%d\n", rcv_buf);
    printf("OUTPUT :%d\n", snd_buf);
    close(sock);
    return 0;
}

Compile run:

gcc set_buf.c -o set_buf
./set_buf

Operation result:

INPUT : 6144
OUTPUT : 6144

The running result is not as expected, because the buffer size setting needs to be very careful, it will not be completely changed according to our requirements, and it will automatically guarantee a little space.

2. SO_REUSEADDR

Changing the state of the option so ﹣ reuseaddr can determine whether the socket port number in the time wait state can be assigned to a new socket.

The default value of 0 means that a new socket cannot be assigned in this state. Changing to 1 means that it can be assigned.

2.1 what is the time wait state

When a socket disconnects, it experiences four handshakes, whether it calls close() or Ctrl +c

Disconnect the connection first, send the FIN message first, and the received one will turn on the time wait state. In order to wait and judge whether your ACK has been sent, if your ACK can't be sent, the socket will be closed. If the other end times out, it will mistakenly think that the FIN hasn't been sent until it has been resend. So it's just to wait for the FIN not to be resend to judge whether your send is successful. So the general waiting time is about 3 minutes .

In fact, both the server and the client have to go through a period of time wait process. The socket that disconnects first must go through the time wait process. However, since the port of the client socket is arbitrary, there is no need to pay too much attention to the time wait state

That's why address allocation fails when running the same disconnected meeting immediately after disconnection.

2.2 change the so? Reuseaddr option

To determine that the same port will run a new socket immediately after shutdown.

  • [reuseadr_eserver.c]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define mx 1024
void error_handling(char *message);


int main(int argc, char* argv[]) {
    int ser_sock, cli_sock;
    struct sockaddr_in ser_adr, cli_adr;
    socklen_t cli_adr_sz;
    int state, str_len;
    char message[mx];
    ser_sock = socket(PF_INET, SOCK_STREAM, 0);

    if (ser_sock == -1)
        error_handling("socket() error");
    int option;
    int optlen = sizeof(option);
    option = 1;
    state = setsockopt(ser_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen);
    if (state)
        error_handling("setsockopt() error");
    memset(&ser_adr, 0, sizeof(ser_adr));
    ser_adr.sin_family = AF_INET;
    ser_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    ser_adr.sin_port = htons(atoi(argv[1]));
    if (bind(ser_sock, (struct sockaddr*)&ser_adr, sizeof(ser_adr)) == -1)
        error_handling("bind() error");
    if (listen(ser_sock, 5) == -1)
        error_handling("listen() error");
    cli_adr_sz = sizeof(cli_adr);
    cli_sock = accept(ser_sock, (struct sockaddr*)&cli_adr, &cli_adr_sz);
    if (cli_sock == -1)
        error_handling("socket() error_cli");
    while ((str_len = read(cli_sock, message, sizeof(message))) != 0) {
        write(cli_sock, message, str_len);
//        write(1, message, str_len);
    }
//    shutdown(ser_sock, SHUT_WR);
    close(cli_sock);
    close(ser_sock);
    return 0;
}

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

Compile run:

gcc reuseadr_eserver.c -o reuseadr_eserver
./reuseadr_eserver 9190
^c
./reuseadr_eserver 9190

Operation result:

No report error

Phenomenon: the client can only be closed after the server is closed. After the server is closed, it can reconnect before the client is closed.

3. TCP_NODELAY

Set the usage status of the Nagle algorithm.

3.1 what is the Nagle algorithm

Nagle algorithm is to send the next data only after receiving the reply ACK of the previous data. Using and sending short messages can improve the network transmission efficiency.

Because it can send more data to the buffer next time when it is waiting, so as to reduce the use of packets. Each packet will have header information. Reducing the use can also reduce the network traffic.

This is only applicable to small file transfer, while the input and output buffers of large file transfer will not take too much time, and will be transferred when the data buffer package is full, so it will not increase the use of data packages. Therefore, if the Nagle algorithm is not used, the efficiency can be greatly improved.

3.2 disable Nagle algorithm

Just change TCP? Nodelay to 1 (true)

int opt_val = 1  
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &opt_val, sizeof(opt_val)); // Set up
socklen_t  opt_len = sizeof(opt_val);
getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &opt_val, &opt_len ); //See
Published 60 original articles, won praise 26, visited 20000+
Private letter follow

Keywords: socket network github Programming

Added by patelp7 on Tue, 11 Feb 2020 13:02:46 +0200