socket编程实现TCP通信

发布于:2024-04-19 ⋅ 阅读:(32) ⋅ 点赞:(0)

socket编程实现TCP通信

tcp_client.cc

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <cerrno>
#include "log.hpp"
#define SIZE 1024
uint16_t serverport;
std::string serverip;
void *tcpSend(void *args)
{
    int sock = *(int *)args;

    std::string message;
    while (true)
    {
        std::cerr << "请输入你的信息# ";
        std::getline(std::cin, message);
        send(sock, message.c_str(), message.size(), 0);
    }
}

void *tcpRecv(void *args)
{
    int sock = *(int *)args;
    char buff[1024];
    while (true)
    {
        ssize_t s = recv(sock, buff, sizeof(buff) - 1, 0);
        if (s > 0)
        {
            buff[s] = '\0';
            printf("%s\n", buff);
            fflush(stdout);
        }
    }
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " ip port" << std::endl;
        exit(1);
    }
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "FATAL " << errno << ":" << strerror(errno);
        exit(2);
    }

    serverport = atoi(argv[2]);
    serverip = argv[1];

    struct sockaddr_in server;
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1) {
        printf("连接失败 [%d:%s]\n",errno,strerror(errno));
        close(sock);
        exit(1);
    }
    LogMessage(NORMAL,"connect success");

    pthread_t t1, t2;
    pthread_create(&t1, nullptr, tcpSend, (void *)&sock);
    pthread_create(&t2, nullptr, tcpRecv, (void *)&sock);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);

    close(sock);
    return 0;
}

tcp_server.cc

#include "tcp_server.hpp"
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        std::cout<<"Usage: "<<argv[0]<<" port"<<std::endl;
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    TcpServer* svr = new TcpServer(port);
    svr->initServer();
    svr->start();
    delete svr;
    return 0;
}

tcp_server.hpp

#ifndef UDP_SERVER_HPP
#define UDP_SERVER_HPP

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include "log.hpp"

#define SIZE 1024

static void service(int sock, std::string &client_ip, uint16_t &client_port)
{
    char buff[1024];
    while (true)
    {
        ssize_t s = read(sock, buff, sizeof(buff) - 1);
        if (s > 0)
        {
            buff[s] = '\0';
            printf("[%s:%d]# %s\n", client_ip.c_str(), client_port, buff);
        }
        else if (s == 0)
        {
            LogMessage(NORMAL, "[%s:%d] shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else
        {
            LogMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(sock, buff, strlen(buff));
    }
}
struct ThreadData
{
    int _sock;
    std::string _ip;
    uint16_t _port;
};
class TcpServer
{
private:
    const int gbacklog = 20;

public:
    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = (ThreadData*)args;
        service(td->_sock, td->_ip, td->_port);
        delete td;
        return nullptr;
    }
    TcpServer(uint16_t port, std::string ip = "0.0.0.0")
        : _port(port), _listensock(-1),_ip(ip)
    {
    }
    void initServer()
    {
        // 创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LogMessage(FATAL, "socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }
        // 绑定
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            LogMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }
        // 建立连接(监听)
        if (listen(_listensock, gbacklog) < 0)
        {
            LogMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        LogMessage(NORMAL, "init TCP server success, listensock: %d", _listensock);
    }
    void start()
    {
        signal(SIGCHLD,SIG_IGN);//不理会子进程 v2.1
        while (true)
        {
            // 获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int servicesock = accept(_listensock, (struct sockaddr *)&src, &len);
            std::cout<<servicesock<<std::endl;
            if (servicesock < 0)
            {
                LogMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            LogMessage(NORMAL, "link success, [%s:%d]", client_ip.c_str(), client_port);
            // 获取连接成功,开始通信服务
            // v1 单进程循环
            //service(servicesock, client_ip, client_port);

            //v2.0 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     service(servicesock, client_ip, client_port);
            //     exit(0);
            // }
            // close(servicesock);

            //v2.1 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     if(fork() > 0) exit(0);
            //     service(servicesock, client_ip, client_port);
            // }
            // waitpid(id,nullptr,0);
            // close(servicesock);

            //v3 多线程
            ThreadData* td = new ThreadData;
            td->_sock = servicesock;
            td->_ip = client_ip;
            td->_port = client_port;
            pthread_t tid;
            pthread_create(&tid,nullptr,threadRoutine,(void*)td);
            close(servicesock);


        }
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};
#endif

log.hpp

#pragma once
#include<iostream>
#include<cstdio>
#include<cstdarg>
#include<ctime>
#include<string>

#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4
const char* gLevelMap[]={"DEBUG","NORMAL","WARNING","ERROR","FATAL"};

void LogMessage(int level,const char* format,...)
{
    char stdBuffer[1024] = {'\0'};
    time_t timestamp = time(nullptr);
    snprintf(stdBuffer,sizeof stdBuffer,"[%s] [%ld]",gLevelMap[level],timestamp);

    char logBuffer[1024] = {'\0'};;
    va_list args;
    va_start(args,format);
    vsnprintf(logBuffer,sizeof logBuffer,format,args);
    va_end(args);
    printf("%s%s\n",stdBuffer,logBuffer);
}

makefile

.PHONY:add
all:tcp_client tcp_server
tcp_client:tcp_client.cc
	g++ -o $@ $^ -std=c++11 -l pthread
tcp_server:tcp_server.cc
	g++ -o $@ $^ -std=c++11 -l pthread
.PHONY:clean
clean:
	rm -f tcp_client tcp_server