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

这篇具有很好参考价值的文章主要介绍了【C/C++套接字编程】TCP协议通信的简单实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一、TCP_Server.cpp

二、TCP_Client.cpp

三、TCP Server.cpp (多线程)

总结


系列博客

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

【C/C++套接字编程】TCP通信实验_Mr_Fmnwon的博客-CSDN博客

【C/C++套接字编程】UDP协议通信的简单实现_Mr_Fmnwon的博客-CSDN博客

【C/C++套接字编程】UDP通信实验_Mr_Fmnwon的博客-CSDN博客


前言

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

参考文献 

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


一、TCP_Server.cpp

//server.cpp
#include <stdio.h>
#include <Winsock2.h>
#include <time.h>
#include <string.h>
#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<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(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 interactive(SOCKET socket_of_client,struct sockaddr_in c_sin)
{
    // int c_sin_len = sizeof(struct sockaddr_in);
    char recvData[200];
    char sendData[200];
    print_time();
    printf("接收到一个连接:%s\\r\\n", inet_ntoa(c_sin.sin_addr));
    while (1)
    {
        recvData[0] = '\\0';
        //part6 读取消息
        int ret = recv(socket_of_client,recvData, 199, 0);
        //part6 end
        if (ret < 0)
        {
            print_time();
            printf("***Something wrong***\\n");
            continue;
        }
        recvData[ret] = '\\0';
        // 如果客户端发送了quit,那么就退出
        if (strcmp(recvData, "quit") == 0)
            break;
        print_time(c_sin.sin_addr);
        printf("读取消息:");
        printf("%s\\n", recvData);

        printf("请发送消息:");
        gets(sendData);
        // space2_(sendData);
        print_time();
        printf("发送消息:%s",sendData);
        printf("\\n");
        //part7 发送消息
        send(socket_of_client, sendData, 199, 0);
        //part7 end
        if (strcmp("quit", sendData) == 0)
            break;
    }
}


二、TCP_Client.cpp

//client.cpp
#include <winsock2.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <direct.h>
#include <time.h>
#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 <stdio.h>
#include <Winsock2.h>
#include <time.h>
#include <string.h>
#include <thread>
#include <iostream>
#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通信的相关过程与细节,还需要加深理解文章来源地址https://www.toymoban.com/news/detail-489168.html

到了这里,关于【C/C++套接字编程】TCP协议通信的简单实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

    为什么需要网络编程? 现在网络普及程序越来越高,网络上保存着我们日常生活中需要的各种资源,使用程序通过网络来获取这些资源的过程就需要网络编程来实现。 什么是网络编程? 网络编程,指网络上的主机,通过不同的进程以程序的方式实现网络通信(网络数据传输)

    2024年02月17日
    浏览(79)
  • 【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的TCP网络程序模拟实现 。通过本文的学习,读者将能够深入了解TCP协议的实际应用,并掌握如何编写简单的TCP网络程序。让我们一起深入探讨TCP网络程序的

    2024年04月14日
    浏览(87)
  • 【网络通信】socket编程——TCP套接字

    TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 通过TCP的套接字 ,来把数据交付给对方的应用层,完成双方进程的通信 在 tcpServer.hpp 中,创建一个命名空间 yzq 用于封装 在命名

    2024年02月13日
    浏览(51)
  • 【网络编程】利用套接字实现一个简单的网络通信(UDP实现聊天室 附上源码)

    源IP地址(Source IP Address): 源IP地址是数据包发送方(或数据流出发点)的唯一标识符。它用于在互联网或本地网络中定位发送数据包的设备或主机。源IP地址是数据包的出发点,即数据从这个地址开始传送,向目的IP地址指示的设备发送。 在TCP/IP协议中,源IP地址通常由发

    2024年02月14日
    浏览(86)
  • Liunx 套接字编程(2)TCP接口通信程序

    面向连接、可靠传输、提供字节流传输服务 客户端向服务器发送一个连接建立的请求流程,上图中服务端第三步详细流程 socket--创建套接字 bind---绑定 sockfd : socket返回的套接字描述符 addr: 要绑定的地址信息(不同地址域类型,有不同的地址结构) listen--监听 注意:listen第二

    2024年02月08日
    浏览(71)
  • 学习网络编程No.5【TCP套接字通信】

    北京时间:2023/8/25/15:52,昨天刚把耗时3天左右的文章更新,充分说明我们这几天并不是在摆烂中度过,而是在为了更文不懈奋斗,历时这么多天主要是因为该部分知识比较陌生,所以需要我们花费大量的时间去细细研究,为后面无论是TCP套接字,还是网络的学习都能更加融会

    2024年02月10日
    浏览(61)
  • [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

    网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现…

    2024年02月16日
    浏览(66)
  • socket套接字通信 TCP传输控制协议/IP网络协议 5.18

    B/S :浏览器和服务器 C/S :客户机和服务器 网络的层次结构和每层所使用协议的集合 网络采用分层管理的方法,将网络的功能划分为不同的模块 OSI模型: 共7种: 数据的封装与传递过程: 网络传输数据大小user data: 6~1460 网络传输中容易发生拆包和粘包,所以接收和发送的字节

    2024年02月05日
    浏览(78)
  • Python入门【TCP建立连接的三次握手、 TCP断开连接的四次挥手、套接字编程实战、 TCP编程的实现、TCP双向持续通信】(二十七)

    👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白 📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的

    2024年02月12日
    浏览(42)
  • 网络编程套接字(2)——简单的TCP网络程序

    我们将TCP服务器封装成一个类,当我们定义出一个服务器对象后需要马上对服务器进行初始化,而初始化TCP服务器要做的第一件事就是创建套接字。 TCP服务器在调用socket函数创建套接字时,参数设置如下: 协议家族选择 AF_INET ,因为我们要进行的是网络通信。 创建套接字时

    2024年02月06日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包