TCP/IP network programming learning note disconnect socket

Posted by kpzani on Wed, 27 Nov 2019 17:56:08 +0100

I. TCP based half shutdown

1. Problems caused by unilateral disconnection

The close function of Linux and the closesocket function of Windows mean complete disconnection. Complete disconnection means that the input and output streams are disconnected at the same time. If host A no longer needs to transmit data to host B, and host A has data from host B that must be received, A complete disconnection will result in data loss. Semi closed flow (only A part of the flow used in data exchange can be closed, data can be transmitted but not received, or data can be received but not transmitted) can solve this problem.

2. Correlation function

Shutdown function: at the end of file transfer, the close function not only closes the I/O stream, but also sends EOF to the other party, which means the end of file transfer. The other party receives EOF through the function return value. The shutdown function only closes part of the stream, and also sends EOF to the other party

#include<sys/socket.h>
// Function: half closed flow
// Parameters:
//    Socket -- sock et file descriptor to disconnect
//    howto -- delivering disconnection information
// Return value: 0 on success and - 1 on failure
int shutdown(int sock,int howto);

Optional value of howto parameter:

  • Shut? Rd: disconnect input stream
  • Shut? WR: disconnect output stream
  • Shtu? Rdwr: simultaneously disconnect I/O flow

3. Verification procedure

The server sends files to the client, and the client sends back "Thank you" after receiving the files

  • file_server.c
#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, clnt_sock;
    struct sockaddr_in serv_addr, clnt_addr;
    char buf[BUF_SIZE];
    FILE* fp;

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

    fp = fopen("file_server.c", "rb");

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

    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");

    while (1) {
        // When the free function succeeds, it returns the same value as the third parameter, BUF_SIZE. If the return value is greater than 0 and less than BUF_SIZE,
        // If the return value is 0, the number of bytes read is less than the number of bytes specified by the second parameter, and the read fails
        int read_cnt = fread((void*)buf, 1, BUF_SIZE, fp);
        if (read_cnt < BUF_SIZE) {
            write(clnt_sock, buf, read_cnt);
            break;
        }
        write(clnt_sock, buf, BUF_SIZE);
    }

    shutdown(clnt_sock, SHUT_WR);
    read(clnt_sock, buf, BUF_SIZE);
    printf("Message form client: %s \n", buf);

    fclose(fp);
    close(clnt_sock);
    close(serv_sock);
    return 0;
}
  • file_client.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUF_SIZE 30

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

int main(int argc, char* argv[]) {
    int sock;
    struct sockaddr_in serv_addr;
    char buf[BUF_SIZE];
    FILE* fp;

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

    fp = fopen("receive.dat", "wb");

    sock = socket(PF_INET, SOCK_STREAM, 0);

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

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

    int read_cnt;
    while ((read_cnt = read(sock, buf, BUF_SIZE)) != 0)
        fwrite((void*)buf, 1, read_cnt, fp);

    puts("Received file data");
    write(sock, "Thank you", 10);

    fclose(fp);
    close(sock);
    return 0;
}
  • Operation result

Reference books: TCP/IP network programming Written by Yin Shengyu, translated by Jin GuoZhe

Topics: socket less Linux Windows