程式語言 - MinGW - C/C++ - Console - TCP Server、Client



參考資訊:
https://www.geeksforgeeks.org/socket-programming-cc/

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

int main(int argc, char *argv[])
{
    int r = 0;
    int opt = 1;
    SOCKET fd = INVALID_SOCKET;
    SOCKET new_socket = INVALID_SOCKET;
    char buf[255] = { 0 };
    char client_ip[INET_ADDRSTRLEN] = {  0};
    struct sockaddr_in addr = { 0 };
    struct sockaddr_in client_addr = { 0 };
    int addrlen = sizeof(client_addr);
    const char *hello = "hello from server !";
    WSADATA wsaData = { 0 }; 

    if (argc != 3) {
        printf("Usage: %s IP Port\n", argv[0]);
        return 0;
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        printf("WSAStartup failed: %d\n", WSAGetLastError());

        return 1;
    }

    fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd == INVALID_SOCKET) {
        printf("socket() failed: %d\n", WSAGetLastError());
        WSACleanup();

        return 1;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) == SOCKET_ERROR) {
        printf("setsockopt() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons((u_short)atoi(argv[2]));
    if (InetPtonA(AF_INET, argv[1], &addr.sin_addr) != 1) {
        printf("Invalid IP address: %s\n", argv[1]);
        closesocket(fd);
        WSACleanup();

        return 1;
    }

    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
        printf("bind() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }

    if (listen(fd, 3) == SOCKET_ERROR) {
        printf("listen() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }
    printf("Server listening on %s:%s\n", argv[1], argv[2]);

    new_socket = accept(fd, (struct sockaddr *)&client_addr, &addrlen);
    if (new_socket == INVALID_SOCKET) {
        printf("accept() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }

    if (InetNtopA(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip))) {
        printf("Client connected from %s:%u\n", client_ip, ntohs(client_addr.sin_port));
    }

    r = recv(new_socket, buf, sizeof(buf) - 1, 0);
    if (r == SOCKET_ERROR) {
        printf("recv() failed: %d\n", WSAGetLastError());
    } else if (r == 0) {
        printf("Client closed connection\n");
    } else {
        buf[r] = '\0';
        printf("%s (r=%d)\n", buf, r);
    }

    if (r > 0) {
        r = send(new_socket, hello, (int)strlen(hello), 0);
        if (r == SOCKET_ERROR) {
            printf("send() failed: %d\n", WSAGetLastError());
        }
    }

    closesocket(new_socket);
    closesocket(fd);
    WSACleanup();

    return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

int main(int argc, char *argv[])
{
    int r = 0;
    SOCKET fd = INVALID_SOCKET;
    char buf[255] = { 0 };
    struct sockaddr_in addr = { 0 };
    const char *hello = "hello from client !";
    WSADATA wsaData;

    if (argc != 3) {
        printf("Usage: %s IP Port\n", argv[0]);

        return 0;
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        printf("WSAStartup failed: %d\n", WSAGetLastError());

        return 1;
    }

    fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd == INVALID_SOCKET) {
        printf("socket() failed: %d\n", WSAGetLastError());
        WSACleanup();

        return 1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons((u_short)atoi(argv[2]));
    if (InetPtonA(AF_INET, argv[1], &addr.sin_addr) != 1) {
        printf("Invalid IP address: %s\n", argv[1]);
        closesocket(fd);
        WSACleanup();

        return 1;
    }

    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
        printf("connect() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }
    printf("Connected to %s:%s\n", argv[1], argv[2]);

    r = send(fd, hello, (int)strlen(hello), 0);
    if (r == SOCKET_ERROR) {
        printf("send() failed: %d\n", WSAGetLastError());
        closesocket(fd);
        WSACleanup();

        return 1;
    }
    printf("Sent %d bytes\n", r);

    r = recv(fd, buf, sizeof(buf) - 1, 0);
    if (r == SOCKET_ERROR) {
        printf("recv() failed: %d\n", WSAGetLastError());
    }
    else if (r == 0) {
        printf("Server closed connection\n");
    }
    else {
        buf[r] = '\0';
        printf("%s (r=%d)\n", buf, r);
    }
    closesocket(fd);
    WSACleanup();

    return 0;
}

編譯、執行

$ i686-w64-mingw32-gcc server_win32.c -o server_win32.exe -lws2_32
$ i686-w64-mingw32-gcc client_win32.c -o client_win32.exe -lws2_32
$ ./server_win32.exe 127.0.0.1 8888
    Server listening on 127.0.0.1:8888

$ ./client.exe 127.0.0.1 9999
    Connected to 127.0.0.1:9999
    Sent 19 bytes
    hello from server ! (r=19)
    
    Client connected from 127.0.0.1:38460
    hello from client ! (r=19)