【C/C++】TCP服務端和客戶端Echo案例

C/C++ TCP服務器案例代碼,客戶端業務都新開線程處理,不能用於生產環境,生產環境使用select/epool,或開源庫libevent、asio等處理

TCP服務端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <thread>

#define BUF_SIZE 1024

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("usage: ./server <port>\n");
        return EXIT_FAILURE;
    }

    int server_socket_fd;
    struct sockaddr_in server_addr;
    int on = 1;

    if ((server_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return EXIT_FAILURE;
    }

    if (setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        printf("setsockopt error: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(6666);

    if (bind(server_socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    if (listen(server_socket_fd, 10) == -1)
    {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    printf("======waiting for client's request======\n");
    for (;;)
    {
        struct sockaddr_in client_addr;
        socklen_t address_len = sizeof(client_addr);
        int accept_fd; //客戶端連接Socket_FD
        if ((accept_fd = accept(server_socket_fd, (struct sockaddr *)&client_addr, &address_len)) != -1)
        {
            //打印客戶端連接地址
            printf("client address: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

            //客戶端後臺線程處理業務,避免阻塞主線程,導致主線程無法接收新的客戶端鏈接
            std::thread client_thread([accept_fd, client_addr]() {
                for (;;)
                {
                    char buff[BUF_SIZE];
                    memset(buff, '\0', sizeof(buff));
                    int size = recv(accept_fd, buff, sizeof(buff), 0);
                    if (size <= 0)
                    {
                        printf("client disconnected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                        close(accept_fd);
                        break;
                    }
                    printf("recv msg from client: %s\n", buff);
                    send(accept_fd, buff, sizeof(buff), 0);
                    printf("send msg to client: %s\n", buff);
                }
            });
            client_thread.detach(); //客戶端業務後臺線程,避免註冊主線程監聽新的客戶端連接
        }
        else
        {
            printf("accept socket error: %s\n", strerror(errno));
            continue;
        }
    }
    close(server_socket_fd);
    return 0;
}

TCP客戶端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define BUF_SIZE 1024

int main(int argc, char **argv)
{

    int socket_fd, size;
    char recvline[BUF_SIZE], sendline[BUF_SIZE];
    struct sockaddr_in servaddr;

    if (argc != 3)
    {
        printf("usage: ./client <ipaddress> <port>\n");
        return EXIT_FAILURE;
    }
    const char *host = argv[1];
    int port = atoi(argv[2]);

    if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return EXIT_FAILURE;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    if (inet_pton(AF_INET, host, &servaddr.sin_addr) <= 0)
    {
        printf("inet_pton error for %s\n", host);
        return EXIT_FAILURE;
    }

    if (connect(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
        return EXIT_FAILURE;
    }

    printf("send msg to tcp server: \n");

    for (;;)
    {
        memset(sendline, '\0', sizeof(sendline));
        memset(recvline, '\0', sizeof(recvline));
        fgets(sendline, BUF_SIZE, stdin);
        if (send(socket_fd, sendline, strlen(sendline), 0) < 0)
        {
            printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
            close(socket_fd);
        }
        if (recv(socket_fd, recvline, sizeof(recvline), 0) < 0)
        {
            printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
            close(socket_fd);
            break;
        }
        printf("receive from tcp server: %s\n", recvline);
    }
    close(socket_fd);
    return EXIT_SUCCESS;
}

客戶端效果:

send msg to tcp server: 
zhangsan
receive from tcp server: zhangsan

lisi
receive from tcp server: lisi

wangwu
receive from tcp server: wangwu

服務端效果:

recv msg from client: zhangsan

send msg to client: zhangsan

recv msg from client: lisi

send msg to client: lisi

recv msg from client: wangwu

send msg to client: wangwu
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章