【C/C++套接字编程】TCP协议通信的简单实现

【C++套接字编程】套接字的基本概念与基础语法_Mr_Fmnwon的博客-CSDN博客

目录

前言

一、TCP_Server.cpp

二、TCP_Client.cpp

三、TCP Server.cpp (多线程)

总结


前言

本篇着重于基于socket编程,实现基本的TCP通信。 

参考文献 

C++实现TCP服务器端同时和多个客户端通信(多线程)_多客户端 tcp通信 c++_新西兰做的饭的博客-CSDN博客


一、TCP_Server.cpp

//server.cpp
#include 
#include 
#include 
#include 
#pragma warning(disable : 4996)
#pragma comment(lib, "ws2_32.lib")
#define USER_ERROR -1
using namespace std;
void space2_(char *str);
void print_time();
void print_time(in_addr addr);
//用于交互
void interactive(SOCKET socket_of_client,struct sockaddr_in c_sin);
int main()
{
    WSADATA wsaData;
    // 打开网络库/启动网络库,启动了这个库,这个库里的函数/功能才能使用
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock.\\n");
        return USER_ERROR;
    }
    SOCKET socket_of_server;
    SOCKET socket_of_client;
    //part1 创建socket
    socket_of_server = socket(AF_INET, SOCK_STREAM, 0);
    //part1 end
    // 确保socker创建成功
    if (socket_of_server == INVALID_SOCKET)
    {
        printf("socket() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    //part2 填写套接字信息
    struct sockaddr_in s_sin;
    s_sin.sin_family = AF_INET;
    s_sin.sin_port = htons(20000);
    s_sin.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");
    //part2 end
    //part3 将服务器的socket和服务器的ip地址和端口号绑定
    if (bind(socket_of_server, (struct sockaddr *)&s_sin, sizeof(s_sin)) == SOCKET_ERROR)
    {
        printf("blind() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    //part4 启动监听
    if (listen(socket_of_server,3) == SOCKET_ERROR)
    //part4 end
    {
        print_time();
        printf("listen() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    struct sockaddr_in c_sin;
    int c_sin_len = sizeof(struct sockaddr_in);
    // 不断监听,直到接收到客户端的连接
    printf("==========Waiting for connect...==========\\n");
    while (1)
    {
        //part5 建立tcp连接
        socket_of_client = accept(socket_of_server, (struct sockaddr *)&c_sin, &c_sin_len);
        //part5 end
        if (socket_of_client == INVALID_SOCKET)
        {
            printf("accept() Failed:%d", WSAGetLastError());
            print_time();
        }
        else
        {
            interactive(socket_of_client,c_sin);
        }
    }
    closesocket(socket_of_server);
    WSACleanup();
    return 0;
}

void space2_(char *str)
{
    for(unsigned int i=0; i


二、TCP_Client.cpp

//client.cpp
#include 
#include 
#include 
#include 
#include 
#include 
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4996)
#define USER_ERROR -1

void delete_last_line();
void print_time();
void print_time_from(in_addr addr);
void print_time_to(in_addr addr);
int main()
{
    // time_t now;
    // char* curr_time = time(&now);
    char recvData[200];
    char sendData[200];
    int ret;
    //启动套接字编程,不启动无法运行相关API
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock.\\n");
        return USER_ERROR;
    }
    //part1 创建套接字
    SOCKET socket_client = socket(AF_INET, SOCK_STREAM, 0);
    //end part1
    if (socket_client == INVALID_SOCKET)
    {
        printf(" Failed socket() \\n");
        return 0;
    }
    //part2 设置套接字信息 这里是需要
    struct sockaddr_in server_in;
    server_in.sin_family =AF_INET;
    server_in.sin_port =htons(20000);
    server_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    //part2 end

    printf("=============Trying to connect...=============\\n");
    //part3 连接服务器
    if (connect(socket_client, (struct sockaddr *)&server_in, sizeof(server_in)) == -1)
    //part3 end
    {
        printf(" Failed connect() \\n");
        return 0;
    }
    else
    {
        print_time();
        printf("connect %s.%d\\n", inet_ntoa(server_in.sin_addr),server_in.sin_port);
        while (1)
            {
                memset(recvData,'\\0',sizeof(recvData));
                memset(sendData,'\\0',sizeof(sendData));
                printf("请发送消息:");
                gets(sendData);
                delete_last_line();
                print_time_to(server_in.sin_addr);
                printf("发送消息:【%s】\\n", sendData);

                //part4 发送消息
                send(socket_client, sendData, strlen(sendData), 0);
                //part4 end
                if (strcmp(sendData, "quit") == 0)
                    break;
                recvData[0] = '\\0';
                //part5 接收消息
                ret = recv(socket_client, recvData, 200, 0);
                recvData[ret] = '\\0';
                print_time_from(server_in.sin_addr);
                printf("读取消息:");
                //part5 end
                printf("%s\\n", recvData);
            }
    }
    closesocket(socket_client);
    WSACleanup();
    return 0;
}

void delete_last_line()
{
    printf("\\033[1A"); //先回到上一行
    printf("\\033[K");  //清除该行
    printf("\\r              \\r");
}

void print_time() {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s]", now);
}

void print_time_from(in_addr addr) {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s](From %s):", now, inet_ntoa(addr));
}

void print_time_to(in_addr addr) {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s](To %s):", now, inet_ntoa(addr));
}

三、TCP Server.cpp (多线程)

C++实现TCP服务器端同时和多个客户端通信(多线程)_多客户端 tcp通信 c++_新西兰做的饭的博客-CSDN博客

我们实现了两台机子的互相通信,能不能实现多个机子之间的互相通信呢?仔细想想,这就涉及到同时干多件事情的操作了。因此需要开多线程进行程序的处理。上面参考的博客,也是关于多线程实现服务器和多个客户端通信。(这里的多线程实现了多个用户端和服务端的通信,但是并没有完全完善,存在着服务端需要依次和多个用户端通信的情况,而交互界面也尚待完善)

//server.cpp
#include 
#include 
#include 
#include 
#include 
#include 
#pragma warning(disable : 4996)
#pragma comment(lib, "ws2_32.lib")
#define USER_ERROR -1
using namespace std;
void space2_(char* str);
void print_time();
void print_time_from(in_addr addr);
void print_time_to(in_addr addr);
bool GetAddressBySocket(SOCKET m_socket, SOCKADDR_IN& m_address);
void delete_last_line();
//用于交互
DWORD WINAPI interactive(LPVOID lpThreadParameter);

int main()
{
    WSADATA wsaData;
    // 打开网络库/启动网络库,启动了这个库,这个库里的函数/功能才能使用
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock.\\n");
        return USER_ERROR;
    }
    SOCKET socket_of_server;
    SOCKET socket_of_client;
    //part1 创建socket
    socket_of_server = socket(AF_INET, SOCK_STREAM, 0);
    //part1 end
    // 确保socker创建成功
    if (socket_of_server == INVALID_SOCKET)
    {
        printf("socket() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    //part2 填写套接字信息
    struct sockaddr_in s_sin;
    s_sin.sin_family = AF_INET;
    s_sin.sin_port = htons(20000);
    s_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    //part2 end
    //part3 将服务器的socket和服务器的ip地址和端口号绑定
    if (bind(socket_of_server, (struct sockaddr*)&s_sin, sizeof(s_sin)) == SOCKET_ERROR)
    {
        printf("blind() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    //part4 启动监听
    if (listen(socket_of_server, 3) == SOCKET_ERROR)
        //part4 end
    {
        print_time();
        printf("listen() Failed:%d\\n", WSAGetLastError());
        return USER_ERROR;
    }
    struct sockaddr_in c_sin;
    int c_sin_len = sizeof(struct sockaddr_in);
    // 不断监听,直到接收到客户端的连接
    printf("==========Waiting for connect...==========\\n");
    while (1)
    {
        //part5 建立tcp连接
        socket_of_client = accept(socket_of_server, (struct sockaddr*)&c_sin, &c_sin_len);
        //part5 end
        if (socket_of_client == INVALID_SOCKET)
        {
            printf("accept() Failed:%d", WSAGetLastError());
            print_time();
        }
        else
        {
            HANDLE hThread = CreateThread(NULL, 0, interactive, (LPVOID)socket_of_client, 0,NULL);
        }
    }
    closesocket(socket_of_server);
    WSACleanup();
    return 0;
}

void space2_(char* str)
{
    for (auto i = 0; i < strlen(str); i++)
    {
        if (str[i] == ' ')
        {
            str[i] = '_';
        }
    }
}

void print_time() {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s]", now);
}

void print_time_from(in_addr addr) {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s](From %s):", now, inet_ntoa(addr));
}

void print_time_to(in_addr addr) {
    time_t cur_time;
    time(&cur_time);
    char* now = ctime(&cur_time);
    now[24] = '\\0';
    printf("[%s](To %s):", now, inet_ntoa(addr));
}

DWORD WINAPI interactive(LPVOID lpThreadParameter)
{
    char recvData[200];
    char sendData[200];
    SOCKADDR_IN c_sin;
    print_time();
    SOCKET socket_of_client = (SOCKET)lpThreadParameter;
    GetAddressBySocket(socket_of_client,c_sin);
    printf("接收到一个连接:IP(%s)Port(%d)\\r\\n", inet_ntoa(c_sin.sin_addr), ntohs(c_sin.sin_port));
    while (1)
    {
        recvData[0] = '\\0';
        //part6 读取消息
        int ret = recv(socket_of_client, recvData, 199, 0);
        //part6 end
        if (ret < 0)
        {
            //m.lock();
            print_time();
            printf("***Something wrong***\\n");
            //m.unlock();
            continue;
        }
        recvData[ret] = '\\0';
        // 如果客户端发送了quit,那么就退出
        if (strcmp(recvData, "quit") == 0)
            break;
        //m.lock();
        print_time_from(c_sin.sin_addr);
        printf("读取消息:【%s】\\n",recvData);
        //printf("%s\\n", recvData);
        printf("请发送消息:");
        gets_s(sendData);
        // space2_(sendData);
        delete_last_line();
        print_time_to(c_sin.sin_addr);
        printf("发送消息:【%s】\\n", sendData);
        //printf("\\n");
        //m.unlock();
        //part7 发送消息
        send(socket_of_client, sendData, 199, 0);
        //part7 end
        if (strcmp("quit", sendData) == 0)
            break;
    }
}

//通过套接字获取IP、Port等地址信息
bool GetAddressBySocket(SOCKET m_socket, SOCKADDR_IN& m_address)
{
    memset(&m_address, 0,sizeof(m_address));
    int nAddrLen = sizeof(m_address);

    //根据套接字获取地址信息
    if (::getpeername(m_socket, (SOCKADDR*)&m_address, &nAddrLen) != 0)
    {
        //printf("Get IP address by socket Failed!n");
        return false;
    }

    //读取IP和Port
    //cout << "IP: " << ::inet_ntoa(m_address.sin_addr) << "  PORT: " << ntohs(m_address.sin_port) << endl;
    return true;
}

void delete_last_line()
{
    printf("\\033[1A"); //先回到上一行
    printf("\\033[K");  //清除该行
    printf("\\r              \\r");
}

总结

关于TCP通信的相关过程与细节,还需要加深理解

你可能感兴趣的:(套接字编程,计算机网络,网络协议,网络,tcp/ip,套接字编程)