Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux】:Socket编程 TCP

【Linux】:Socket编程 TCP

作者头像
IsLand1314
发布于 2025-01-20 10:15:53
发布于 2025-01-20 10:15:53
70800
代码可运行
举报
文章被收录于专栏:学习之路学习之路
运行总次数:0
代码可运行

1. 前言

在上篇文章里面已经讲了关于 Socket UDP 网络编程的内容,这篇文章我们主要是关于 Socket TCP 网络编程的内容

老样子,先写 Makefile 文件,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.PHONY:all
all:server_tcp client_tcp

server_tcp:UdpServerMain.cc
	g++ -o $@ $^ -std=c++17 -lpthread
client_tcp:UdpClientMain.cc
	g++ -o $@ $^ -std=c++17 -lpthread

.PHONY:clean 
clean:
	rm -f server_tcp client_tcp

2. EchoSever -- 单进程

同样还需要把框架写好

2.1 基本框架

TCPClient.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

int main()
{
    return 0;
}

TCPServer.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "TcpServer.hpp"
#include <memory>

int main()
{
    ENABLE_CONSOLE_LOG();

    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>();
    
    tsvr->InitServer();
    tsvr->start();
    return 0;
}

导入我们之前的 Log.hpp、Common.hpp、Mutex.hpp,然后对我们之前实现的 Common.hpp 也要做一下修改

2.2 listen & accept 函数

在写具体实现代码之前,我们先来了解一些相关知识

🐇 listen

listen 函数是网络编程中的一个重要函数,通常用于将套接字(socket)设置为监听状态,以接受客户端的连接请求。它通常在服务器端使用,与 socketbindaccept 函数配合使用。

函数原型(C/C++)

在 POSIX 系统(如 Linux)中,listen 函数的原型如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int listen(int sockfd, int backlog);

Windows 系统中,listen 函数的原型如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int listen(SOCKET sockfd, int backlog);

参数说明

  1. sockfd
    • 这是一个套接字描述符(socket file descriptor),通常由 socket 函数创建。
    • 在调用 listen 之前,必须先调用 bind 将套接字绑定到一个本地地址和端口。
  2. backlog
    • 这是一个整数,表示等待连接队列的最大长度。
    • 当多个客户端同时尝试连接服务器时,服务器可能无法立即处理所有连接请求。backlog 参数定义了等待连接队列的最大长度。
    • 如果队列已满,新的连接请求可能会被拒绝(客户端会收到 ECONNREFUSED 错误)返回值

返回值

  • 成功:返回 0
  • 失败:返回 -1(在 POSIX 系统中)或 SOCKET_ERROR(在 Windows 系统中),并设置 errno(POSIX)或调用 WSAGetLastError(Windows)来获取错误代码。
🐇 accept

accept 函数是网络编程中的一个核心函数,用于服务器端接受客户端的连接请求。它通常在 socketbindlisten 之后调用,用于从监听队列中取出一个客户端连接,并创建一个新的套接字用于与客户端通信。

函数原型(C/C++)

在 POSIX 系统(如 Linux)中,accept 函数的原型如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

在 Windows 系统中,accept 函数的原型如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SOCKET accept(SOCKET sockfd, struct sockaddr *addr, int *addrlen);

参数说明

  1. sockfd
    • 这是一个监听套接字描述符(socket file descriptor),通常由 socket 创建并通过 bindlisten 设置为监听状态。
  2. addr
    • 这是一个指向 struct sockaddr 的指针,用于存储客户端的地址信息(如 IP 地址和端口号)。
    • 如果不需要客户端的地址信息,可以将其设置为 NULL
  3. addrlen
    • 这是一个指向 socklen_t(POSIX)或 int(Windows)的指针,表示 addr 结构体的大小。
    • 在调用 accept 之前,需要将其初始化为 addr 结构体的大小。
    • 调用完成后,addrlen 会被设置为实际存储的地址信息的长度。

返回值

  • 成功
    • 返回一个新的套接字描述符(POSIX 中是 int,Windows 中是 SOCKET),用于与客户端通信。
    • 这个新的套接字与监听套接字不同,专门用于与客户端进行数据交换。
  • 失败
    • 返回 -1(POSIX)或 INVALID_SOCKET(Windows),并设置 errno(POSIX)或调用 WSAGetLastError(Windows)来获取错误代码。
🐇 listen 和 accept 使用步骤

listenaccept 函数通常用于服务器端,典型的使用步骤如下:

  1. 调用 socket 创建一个套接字。
  2. 调用 bind 将套接字绑定到一个本地地址和端口。
  3. 调用 listen 将套接字设置为监听状态。
  4. 调用 accept 接受客户端的连接请求。
  5. 使用 accept 返回的新套接字与客户端通信。
  6. 通信完成后,关闭新套接字。
2.3 TcpServer.hpp
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "Log.hpp"
#include "Common.hpp"

#define BACKLOG 8

using namespace LogModule;
static const uint16_t gport = 8080;

class TcpServer
{
public:
    TcpServer(int port = gport): _port(port), _isrunning(false)
    {
    }

    void InitServer()
    {
        // 1. 创建 Tcp Socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // TCP SOCKET
        if(_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket";
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket create success, socked is : " << _listensockfd;  

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));;
        local.sin_family = AF_INET;
        local.sin_port = htons(gport);
        local.sin_addr.s_addr = INADDR_ANY;

        // 2. bind
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success, sockfd is : " << _listensockfd;
        
        // 3.cs, tcp 是面向连接的,因此需要 tcp 随时随地等待被连接 
        // tcp 需要将 socket 设置为监听状态
        n = ::listen(_listensockfd, BACKLOG);
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            Die(SOCKET_ERR);
            
        }
        LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;

    }

    void start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // 不能直接读取数据
            // 1. 获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen;
            int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);
            if(sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accepet error: " << strerror(errno); 
            }

            // 获取连接成功
            LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;
        }
    }

    void Stop()
    {
        _isrunning = true;
    }

    ~TcpServer()
    {
    }

private:
    int _listensockfd; // 监听 socket
    uint16_t _port;
    bool _isrunning;
};

验证

当我们打开浏览器的时候,其实它底层用的就是 TCP,比如我们访问网站输入其网站即可,我们的云服务器其实也是网站一个公开的服务,拿浏览器模拟访问云服务器,如下:

为啥会一次性弹出这么多呢?

原因:因为浏览器服务器它在访问的时候,是多线程的去访问我们的多种资源的,我们的 4、5、6、7 就是 它同时打开的多个资源,相当于多线程多次向服务端发生的连接

我们这里其实是有点问题的

🔥 在调用 accept() 函数时,需要让 socklen_t peerlen = sizeof(peer); 这一行代码的作用是为 peerlen 变量赋初值,表示 struct sockaddr_in peer 结构体的大小。这个初值是必要的

还记得我们上面说的 accept() 原型嘛

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

在调用 accept() 时,addrlen 既是输入参数,也是输出参数:

  • 输入:调用者需要告诉accept() 函数,addr 缓冲区的大小是多少(即 sizeof(peer))。
  • 输出accept() 函数会将实际写入 addr 的客户端地址信息的大小写回到 addrlen 中。

为什么需要 peerlen = sizeof(peer)

  • 初始化缓冲区大小
    • peerlen 需要被初始化为 sizeof(peer),以告诉 accept() 函数,peer 缓冲区的大小是多少。
    • 如果没有初始化 peerlenaccept() 函数将无法知道 peer 缓冲区的大小,可能导致缓冲区溢出或未定义行为。
  • 输出实际地址信息大小
    • accept() 函数会将实际写入 peer 的客户端地址信息的大小写回到 peerlen 中。
    • 例如,如果客户端地址信息的大小是 16 字节,accept() 会将 peerlen 更新为 16。
2.4 HandlerRequest

这里网站一直在转,是因为我们还没有实现其对应的操作,在 TcpServer.cc 操作如下:

函数实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void HandlerRequest(int sockfd) // TCP 同UDP 一样,也全双工通信
{
    LOG(LogLevel::INFO) << "HandlerRequest, sockfd is : " << sockfd;
    char inbuffer[4096];
    while (true)
    {
        // 读取客户端数据
        ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
        if (n > 0)
        {
            inbuffer[n] = 0; // 确保字符串以 null 结尾
            std::string echo_str = "server echo# ";  // 回显数据给客户端
            echo_str += inbuffer;

            ::write(sockfd, echo_str.c_str(), echo_str.size());
        }
    }
}
telnet

使用如下:

退出的话 CTRL + ],再输入 quit 即可

测试如下:

2.5 TcpClient.cc -- 客户端

上面我们已经把服务器的内容写了,下面我们开始对客户端 TcpClient.cc 进行编写

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// ./client_tcp server_ip server_port
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        std::cout << "Usage:./client_tcp server_ip server_port" << std::endl;
        return 1;
    }

    // 获取 server ip 和 port
    std::string server_ip = argv[1]; // "192.168.1.1" 点分十进制的 ip 地址
    int server_port = std::atoi(argv[2]);

    // 创建 socket
    int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        std::cout << "Error: Failed to create socket" << std::endl;
        return 2;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());

    // client 不需要显示的进行 bind,tcp 是面向连接的协议,需要先建立连接
    int n = ::connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(n < 0)
    {
        std::cout << "Error: Failed to connect to server" << std::endl;
        return 3;
    }
    // 发送数据
    std::string message;
    while(true)
    {
        char inbuffer[1024];
        std::cout << "input message: " ;
        std::getline(std::cin, message);

        n = ::write(sockfd, message.c_str(), message.size());
        if(n > 0)
        {
            int m = ::read(sockfd, inbuffer, sizeof(inbuffer));
            if(m > 0)
            {
                inbuffer[m] = 0;
                std::cout << inbuffer << std::endl;
            }
            else break;
        }
        else break;
    }

    ::close(sockfd);
    return 0;
}

演示如下:

2.6 fd 浪费

文件描述符(File Descriptor, FD)泄露是指程序在运行过程中打开了文件或其他资源(如套接字、管道等),但没有正确关闭它们,导致这些文件描述符一直占用系统资源的情况。文件描述符泄露会导致系统资源耗尽,进而引发程序崩溃或系统性能下降。

我们的上面代码其实就存在 fd 泄露问题,当我们直接退出服务器的时候,再连接就会出现 bind 问题,因此我们还需要做点修改

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void HandlerRequest(int sockfd) // TCP 同UDP 一样,也全双工通信
{
    LOG(LogLevel::INFO) << "HandlerRequest, sockfd is : " << sockfd;
    char inbuffer[4096];
    while (true)
    {
        memset(inbuffer, 0, sizeof(inbuffer)); // 清空缓冲区
        // 读取客户端数据
        ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
        if (n > 0)
        {
            LOG(LogLevel::INFO) << inbuffer;
            inbuffer[n] = 0; // 确保字符串以 null 结尾
            std::string echo_str = "server echo# ";  // 回显数据给客户端
            echo_str += inbuffer;

            ::write(sockfd, echo_str.c_str(), echo_str.size());
        }
        else if (n == 0)
        {
            // read 如果读取返回值为 0,表示 client 退出
            LOG(LogLevel::INFO) << "client quit: " << sockfd;
            break;
        }
        else
        {
            // 处理 read 错误
            if (errno == EINTR) {
                continue; // 信号中断,重试
            }
            LOG(LogLevel::ERROR) << "read error: " << strerror(errno);
            break;
        }
    }
    // 关闭套接字
    ::close(sockfd); // fd 泄露问题
    LOG(LogLevel::INFO) << "Connection closed, sockfd: " << sockfd;

}

退出时表现如下:

我们再引入我们在上一篇文章 Udp 的 EchoServer 封装的 InetAddr.hpp

演示如下:

  • 我们此时就在一定程度上规避了文件描述符被浪费的问题

3. EchoServer -- 多进程

上面我们写的只是单进程方面的,接下来我们来创建多进程方面的

  • 但是这里有个问题:当前创建出子进程的时候,父进程还需等待子进程,默认这里就阻塞了
  • 但是我们这里是让子进程去做文本处理,如果子进程不退出/不返回,那么父进程不依然阻塞在这里嘛
  • 阻塞之后还是无法accept,这不还是单进程嘛,但是我们还是必须得 wait,因为不 wait ,子进程一推出就会有僵尸问题
  • 此时就需要用到 信号(signal)

上面那个是一种方法,但是这里换一种我们方法,利用到父子进程 fork 的返回值

演示结果如下:

4. EchoServer -- 多线程

ThreadData 结构体如下:

ThreadEntry 函数如下:

结果如下:

5. EchoServer -- 线程池

引入我们之前写的【Linux】:线程库 Thread.hpp 简单封装 Thread.hpp 以及 单例模式下的【Linux】:日志策略 + 线程池(单例模式 Threadpool.hpp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// version-3:线程池版本 比较时候处理短任务
// task_t f = std::bind(&TcpServer::HandlerRequest, this, sockfd); // 构建任务
// ThreadPool<task_t>::getInstance()->Equeue(f);

// 我们这里也可以 Lambda 表达式 --> 需要对Equeue那的T &in 的 & 删去
ThreadPool<task_t>::getInstance()->Equeue([this, sockfd]() {
    this->HandlerRequest(sockfd);
    });

噢其实这里还有个问题,就是我们写的 HandlerRequest 是长任务,但是线程池一般是用于处理短任务的,因此我们对于线程池数量应该调大点

结果如下:

6. 从文件描述符来进行读写 -- recv / send

上面我们使用的 read 和 write 都是文件中进行的读写,假如我们想从 文件描述符 fd 中来读取数据 呢?--> recv / send

7. 远程命令执行

工作:把远程发过来的当作命令字符串,合理的就执行

TcpServer.cc 修改如下:

CommandExec.cc 如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

#include <iostream>
#include <string>
#include <set>

const int line_size = 1024;

class Command
{
public:
    Command()
    {
        _white_list.insert("ls");
        _white_list.insert("pwd");
        _white_list.insert("ls -l");
        _white_list.insert("ll");
        _white_list.insert("touch");
        _white_list.insert("who");
        _white_list.insert("whoami");
    }

    bool SafeCheck(const std::string &cmdstr)
    {
        auto iter = _white_list.find(cmdstr);
        return iter != _white_list.end();
    }

// 给我们一个命令字符串 "ls -l",让你执行,执行完,把结果返回
    std::string Execute(std::string cmdstr)
    {
        // 1. pipe
        // 2. fork + dup2(pipe[1], 1) + exec*, 执行结果给父进程(进程间通信)
        // 3. return
        // popen 就可以完成上面效果
        // FILE *popen(const char *command, const char *type);
        // int pclose(FILE *stream);
        
        if(!SafeCheck(cmdstr))
        {
            return std::string(cmdstr + " 不支持");
        }

        FILE* fp = ::popen(cmdstr.c_str(), "r");
        if(nullptr == fp)
        {
            return std::string("Failed");
        }
        char buffer[line_size];
        std::string result;
        while(true)
        {
            char *ret = ::fgets(buffer, sizeof(buffer), fp);
            if(!ret) break;
            result += ret;
        }
        pclose(fp);
        return result.empty() ? std::string("Done") : result;
    }

private:
    std::set<std::string> _white_list; // 白名单,只让执行一些命令
};

执行结果如下:

8. windows 作为 client 访问 Linux

tcp_client.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <winsock2.h>
#include <iostream>
#include <string>
#pragma warning(disable : 4996)
#pragma comment(lib, "ws2_32.lib")
std::string serverip = "1.12.51.69"; // 填写你的云服务器 ip
uint16_t serverport = 8080; // 填写你的云服务开放的端口号
int main()
{
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0)
	{
		std::cerr << "WSAStartup failed: " << result << std::endl;
		return 1;
	}
	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM,
		IPPROTO_TCP);
	if (clientSocket == INVALID_SOCKET)
	{
		std::cerr << "socket failed" << std::endl;
		WSACleanup();
		return 1;
	}
	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(serverport);
	serverAddr.sin_addr.s_addr = inet_addr(serverip.c_str());
	result = connect(clientSocket, (SOCKADDR*)&serverAddr,
		sizeof(serverAddr));
	if (result == SOCKET_ERROR)
	{
		std::cerr << "connect failed" << std::endl;
		closesocket(clientSocket);
		WSACleanup();
		return 1;
	}
	while (true)
	{
		std::string message;
		std::cout << "Please Enter@ ";
		std::getline(std::cin, message);
		if (message.empty()) continue;
		send(clientSocket, message.c_str(), message.size(), 0);
		char buffer[1024] = { 0 };
		int bytesReceived = recv(clientSocket, buffer,
			sizeof(buffer) - 1, 0);
		if (bytesReceived > 0)
		{
			buffer[bytesReceived] = '\0'; // 确保字符串以 null 结尾
			std::cout << "Received from server: " << buffer <<
				std::endl;
		}
		else
		{
			std::cerr << "recv failed" << std::endl;
		}
	}
	closesocket(clientSocket);
	WSACleanup();
	return 0;
}

输出如下:


9. 共勉

上面代码均可以在我的 gitee 里面看到的 island0920/112 - Gitee.com

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
在学习本章之前,先看【Linux网络编程】Socket编程–UDP:实现服务器接收客服端的消息 | DictServer简单的英译汉的网络字典 | 简单聊天室】,里面详细介绍函数的使用方法,小编在这篇文章不再具体介绍。
南桥
2024/11/14
2110
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
【计算机网络】Linux下简单的TCP服务器(超详细)
如果创建套接字后获得的文件描述符是小于0的,说明套接字创建失败,此时也就没必要进行后续操作了,直接终止程序即可。
咬咬
2025/06/08
1730
【计算机网络】Linux下简单的TCP服务器(超详细)
【计网】从零开始使用TCP进行socket编程 --- 客户端与服务端的通信实现
UDP(用户数据报协议)和TCP(传输控制协议)都是网络通信中常用的传输层协议,它们在数据传输的方式和特性上存在以下特点:
叫我龙翔
2024/09/18
4070
【计网】从零开始使用TCP进行socket编程 --- 客户端与服务端的通信实现
Tcp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/22
950
Tcp协议Socket编程
【Linux】Socket编程—TCP
  下面介绍程序中用到的 socket API,这些函数都在 sys/socket.h 中。
大耳朵土土垚
2025/02/15
6340
【Linux】Socket编程—TCP
Socket编程---TCP篇
但是,并不是说,TCP就是百利而无一害的。前面说了,TCP还有一个特性---面向字节流,这就导致了,目标主机读取到的内容可能并不是完整的源主机发送的内容。此处来填补这个知识。
小灵蛇
2024/09/07
1020
Socket编程---TCP篇
【在Linux世界中追寻伟大的One Piece】Socket编程TCP
由于客户端不需要固定的端口号,因此不必调用bind(),客户端的端口号由内核自动分配。
枫叶丹
2024/11/03
1290
【在Linux世界中追寻伟大的One Piece】Socket编程TCP
【Linux】深入理解网络编程:应用层自定义协议、序列化、TCP粘包问题与Socket封装
我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层。
用户11316056
2024/12/20
2100
【Linux】深入理解网络编程:应用层自定义协议、序列化、TCP粘包问题与Socket封装
【Linux/unix网络编程】之使用socket进行TCP编程
循环接收客户发来的信息并在终端上显示,同时在信息前加入序号并返回给客户端;当从客户接收到bye后不再发送给各户并退出程序。
马三小伙儿
2018/09/12
5810
【Linux】应用层自定义协议与序列化
  定义结构体来表示我们需要交互的信息; 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体; 这个过程叫做 “序列化” 和 “反序列化”。
大耳朵土土垚
2025/02/16
1130
【Linux】应用层自定义协议与序列化
【计网】基于TCP协议的Echo Server程序实现与多版本测试
我们上一篇文章讲解了利用udp协议实现一个简单的echo_server程序,将客户端的数据在服务端打印出来UDP协议。今天我们来讲解利用TCP协议实现的一个简单的echo_server程序,认识并熟悉各个接口的功能以及如何使用!
用户11316056
2024/11/19
2810
【计网】基于TCP协议的Echo Server程序实现与多版本测试
【网络通信】socket编程——TCP套接字
TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 @TOC
lovevivi
2023/11/17
4680
【网络通信】socket编程——TCP套接字
【Linux】用C++实现UDP通信:详解socket编程流程
协议 是计算机或通信系统中,不同实体(如设备、程序、服务等)之间进行交互和通信时,共同遵循的一套规则和标准。它定义了数据的格式、传输方式、错误处理、安全机制等,确保通信双方能够正确理解彼此的信息并完成协作。
用户11305458
2025/04/11
2960
【Linux网络编程】Socket编程--UDP:实现服务器接收客服端的消息
<font color= black face="楷体" size=3><center>🌈个人主页:南桥几晴秋
南桥
2024/10/24
2410
【Linux网络编程】Socket编程--UDP:实现服务器接收客服端的消息
Socket编程实践(2) Socket API 与 简单例程
在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程。该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端。 socket()函数 socket()函数用于创建一个套接字。这就好像购买了一个电话。不过该电话还没有分配号码。 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol
Tencent JCoder
2018/07/02
8990
Linux__之__基于UDP的Socket编程网络通信
本篇博客旨在使用Linux系统接口进行网络通信, 帮助我们更好的熟悉使用socket套接字网络通信, 学会了socket网络通信, 就能发现所谓网络, 不过都是套路而已, 话不多说, 让我们直接进入代码编写部分.
用户11317877
2025/03/24
1650
Linux__之__基于UDP的Socket编程网络通信
【Linux】socket网络编程之TCP
创建子进程后子进程关闭监听描述符,再创建一个“孙子”进程,然后子进程退出,此时孙子进程成为孤儿进程,被系统领养,再进行其他的工作,工作完成后关闭描述符,退出时由系统回收 父进程关闭新创建的描述符,然后父进程进入进程等待,这个进程等待的时间很短甚至没有,因为子进程在创建完“孙子”进程后就退出了,父进程就可以回收掉子进程继续下一轮的循环
s-little-monster
2025/05/13
1710
【Linux】socket网络编程之TCP
【计网】从零开始使用UDP进行socket编程 --- 客户端与服务端的通信实现
我们了解了网络编程的大概,今天我们就来使用UDP协议来实现客户端与服务端之间的通信过程:
叫我龙翔
2024/09/17
3820
序列化和反序列化(Linux)
把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.cc
ljw695
2025/03/12
880
序列化和反序列化(Linux)
Udp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/17
1630
Udp协议Socket编程
推荐阅读
相关推荐
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验