当前位置: 首页 > news >正文

【计网】从零开始使用TCP进行socket编程 --- 客户端与服务端的通信实现

在这里插入图片描述

阵雨后放晴的天空中,
出现的彩虹很快便会消失。
而人心中的彩虹却永不会消失。
--- 太宰治 《斜阳》---

从零开始使用TCP进行socket编程

  • 1 TCP与UDP
  • 2 TCP服务器类
    • 2.1 TCP基础知识
    • 2.2 整体框架设计
    • 2.3 初始化接口
    • 2.4 循环接收接口与服务接口
  • 3 服务端与客户端
  • 测试运行

1 TCP与UDP

我们之前实现了UDP协议下的客户端与服务端的通信。

UDP(用户数据报协议)和TCP(传输控制协议)都是网络通信中常用的传输层协议,它们在数据传输的方式和特性上存在以下特点:

TCP
  1. TCP 是面向连接的协议,意味着在数据传输之前,必须先建立一个连接,完成握手过程。这个连接在数据传输结束之后需要被断开。
  2. TCP 提供了可靠的服务。它确保数据包的顺序传输,并且通过确认(ACK)和重传机制保证数据的可靠性。
  3. TCP 因为需要建立连接、保证数据顺序和可靠性,所以传输速度相对较慢。
  4. TCP 将数据视为一个连续的数据流,确保数据按照发送的顺序到达。
  5. TCP 适用于要求高可靠性的应用,如网页浏览、文件传输(FTP)、电子邮件(SMTP)等。
  6. TCP 头部较大,因为它需要包含更多的信息来管理连接状态和保证数据的可靠性。
UDP
  1. UDP 是无连接的,它发送数据之前不需要建立连接,每个数据报文都是一个独立的信息传输单位。
  2. UDP 不保证数据包的顺序,也不保证数据包的可靠性。如果数据在传输过程中丢失,UDP不会进行重传。
  3. UDP 由于无需建立连接和保证可靠性,通常用于对实时性要求较高的应用,如视频会议和在线游戏,传输速度较快。
  4. UDP 将数据视为独立的、离散的数据包(datagrams),每个数据包独立处理,可能以不同的顺序到达。
  5. UDP 头部较小,处理起来更为高效。
  6. UDP 适用于实时性要求高的应用,如流媒体、实时视频会议(VoIP)、在线游戏等。

通俗理解的话:TCP的传输过程类似管道,数据从一端发送,然后在另一端按顺序接收。UDP传输数据的过程类似送快递,数据报文会一股脑包装在一起发送给接收者!

2 TCP服务器类

2.1 TCP基础知识

• socket()打开一个网络通讯端口,如果成功的话,就像 open()一样返回一个文件描述符;
• 应用程序可以像读写文件一样用 read / write 在网络上收发数据,通过流来进行读取写入!
• 如果 socket()调用出错则返回-1;
• 对于 IPv4, family 参数指定为 AF_INET;
• 对于 TCP 协议,type 参数指定为 SOCK_STREAM, 表示面向流的传输协议
• protocol 参数的介绍从略,指定为 0 即可。

2.2 整体框架设计

下面我们就来设计一下TCP协议下的服务器类:

  1. 成员变量需要整体通信的_listensockfd和端口号_port,后续绑定网络通信接口,从中读取连接流。
  2. 初始化接口InitServer:对端口号进行绑定,将网络通信接口设置为"接听"模式,可以获取外部的链接。
  3. 循环读取接口Loop:从网络通信接口获取连接流与发送者的信息,之后进行数据接收。
  4. 服务端口Service:根据获取的连接流和发送者的信息开始读取接收数据
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include <memory>
#include <string>
#include <cstring>
#include <iostream>
#include <functional>
#include <unistd.h>#include "Log.hpp"
#include "InetAddr.hpp"using namespace log_ns;
//基础信息
const int gport = 8888;
const int gblocklog = 8;
//错误码
enum
{SOCKET_FD = 1,SOCKET_BIND,SOCKET_LISTNE
};class TcpServer
{
public:TcpServer(int port = gport) : _port(port),_listensockfd(-1),_isrunning(false){}// 进行初始化void InitServer(){   }void Loop(){}void Service(int sockfd, InetAddr addr){}~TcpServer(){}private:uint16_t _port;    // 服务器端口int _listensockfd; // 链接文件bool _isrunning;
};

这就是基础的框架。

2.3 初始化接口

InitServer()初始化接口进行的工作很好理解:

  1. 首先创建socket文件,获取到_listensockfd
  2. 然后将服务器结构体的成员进行初始化,将服务器端口与_listensockfd进行绑定
  3. 最后将_listensockfd通过listen函数进入监听状态。

初始化任务就完成了

// 进行初始化void InitServer(){// 创建socket文件 --- 字节流方式_listensockfd = socket(AF_INET, SOCK_STREAM, 0);if (_listensockfd < 0){LOG(FATAL, "socket error!!!\n");exit(SOCKET_FD);}LOG(INFO, "socket create success!!! _listensockfd: %d\n", _listensockfd);// 建立server结构体struct sockaddr_in local;memset(&local , 0 , sizeof(local));local.sin_family = AF_INET;local.sin_addr.s_addr = INADDR_ANY; // 服务器IP一般设置为0local.sin_port = htons(_port); //一定注意主机序列转网络序列// 进行绑定if (::bind(_listensockfd, (struct sockaddr *)&local, sizeof(local)) < 0){LOG(FATAL, "bind error!!!\n");exit(SOCKET_BIND);}LOG(INFO, "bind success!!!\n");// 将_listensockfd文件转换为listening状态!!!if (::listen(_listensockfd, gblocklog) < 0){LOG(FATAL, "listen error!!!\n");exit(SOCKET_LISTNE);}LOG(INFO, "listen success!!!\n");}

2.4 循环接收接口与服务接口

Loop()循环接收接口需要:

  1. 不断从套接字文件中accept获取连接流与客户端信息!
  2. 获取成功后,就可以进行服务了
  3. 服务就是从流中读取数据,然后处理之后再写回流中!!!使用的接口是read与write,文件流中我们对他们很熟悉!!!
void Loop(){_isrunning = true;while (_isrunning){// accept接收sockfdstruct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);if(sockfd < 0){LOG(WARNING, "accept error\n");continue;}InetAddr addr(client);// 读取数据LOG(INFO, "get a new link, client info : %s, sockfd is : %d\n", addr.AddrStr().c_str(), sockfd);// version 0 --- 不靠谱版本Service(sockfd, addr);}_isrunning = false;}
void Service(int sockfd, InetAddr addr){LOG(INFO , "service start!!!\n");while (true){char buffer[1024];ssize_t n = ::read(sockfd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;LOG(INFO , "sockfd read success!!! buffer: %s\n" , buffer);std::string str = "[server echo]#";str += buffer; write(sockfd, str.c_str(), str.size());}else if(n == 0){LOG(INFO , "client %s quit!\n" , addr.AddrStr().c_str());break;}else{LOG(ERROR, "read error: %s\n", addr.AddrStr().c_str());break;}}::close(sockfd);}

这样基础的服务器的通信工作就写好了

3 服务端与客户端

接下来我们来完善一下服务端和客户端的通信逻辑,让他们可以通信起来

服务端简单的创建一个服务器类然后进行初始化和loop就可以了!!!

#include "TcpServer.hpp"int main(int argc , char* argv[])
{if(argc != 2){std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;exit(0);}uint16_t port = std::stoi(argv[1]);std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port);tsvr->InitServer();tsvr->Loop();return 0;
}

客户端稍微复杂一些:

  1. 首先根据传入的参数进行初始化服务器IP地址和端口号
  2. 然后创建套接字文件 ,并进行connect连接绑定bind,客户端回被动绑定一个端口号!!!
  3. 绑定成功之后就可以通过sockfd进行写入与读取了!!!
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#include <memory>
#include <string>
#include <cstring>
#include <iostream>#include "Log.hpp"using namespace log_ns;int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;exit(0);}std::string ip = argv[1];uint16_t port = std::stoi(argv[2]);// 创建socket文件int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){LOG(FATAL, "sockfd create error!!!\n");exit(1);}struct sockaddr_in server;memset(&server, 0, sizeof(server)); // 数据归零server.sin_family = AF_INET;server.sin_port = htons(port); // 端口号 主机序列转网络序列!!!::inet_pton(AF_INET, ip.c_str(), &server.sin_addr);//安全写入// 进行发送数据int n = ::connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){std::cerr << "connect socket error" << std::endl;exit(2);}// 链接成功while (true){// 进行写入std::string line;std::cout << "Please Enter: ";std::getline(std::cin, line);::write(sockfd, line.c_str(), line.size());LOG(DEBUG , "write success !!!\n");// 读取数据char buffer[1024];int n = read(sockfd, buffer, sizeof(buffer));if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl;}else{break;}}::close(sockfd);return 0;
}

测试运行

我们来测试一下服务端和客户端是否可以做到通信:
在这里插入图片描述
很好,可以完美的进行通信!!!

之后我们就可以加入多线程,加入回调函数逻辑,就可以进行业务处理了!!!

相关文章:

【计网】从零开始使用TCP进行socket编程 --- 客户端与服务端的通信实现

阵雨后放晴的天空中&#xff0c; 出现的彩虹很快便会消失。 而人心中的彩虹却永不会消失。 --- 太宰治 《斜阳》--- 从零开始使用TCP进行socket编程 1 TCP与UDP2 TCP服务器类2.1 TCP基础知识2.2 整体框架设计2.3 初始化接口2.4 循环接收接口与服务接口 3 服务端与客户端测试…...

Imagen:重塑图像生成领域的革命性突破

目录 引言 一、Imagen模型的技术原理 1. 模型概述 2. 工作流程 3. 技术创新 二、Imagen模型的应用实例 1. 创意设计 2. 虚拟角色制作 3. 概念可视化 三、Imagen模型的优势与挑战 1. 优势 2. 挑战 四、Imagen模型的未来发展方向 1. 图像生成质量的提升 2. 多模态…...

Golang | Leetcode Golang题解之第402题移掉K位数字

题目&#xff1a; 题解&#xff1a; func removeKdigits(num string, k int) string {stack : []byte{}for i : range num {digit : num[i]for k > 0 && len(stack) > 0 && digit < stack[len(stack)-1] {stack stack[:len(stack)-1]k--}stack app…...

c++ gtsam/inference/Symbol.h 详细介绍

gtsam/inference/Symbol.h 是 GTSAM 库中的一个头文件&#xff0c;定义了 Symbol 类。这个类用于在因子图优化中标识和管理变量。Symbol 提供了一种便捷的方式来创建和使用唯一标识符&#xff0c;从而避免手动管理复杂的整数键。 Symbol 类详细介绍 Symbol 类是 GTSAM 中用于…...

apache文件共享和访问控制

实现apache文件共享 文件共享路径 <Directory "/var/www/html"> #默认发布路径&#xff0c;功能限制 Options Indexes FollowSymLinks #indexes支持文件共享功能 AllowOverride None Require all granted </Directory> 进入到该路径下 cd…...

LeetCode 2398.预算内的最多机器人数目:滑动窗口+单调队列——思路清晰的一篇题解

【LetMeFly】2398.预算内的最多机器人数目&#xff1a;滑动窗口单调队列——思路清晰的一篇题解 力扣题目链接&#xff1a;https://leetcode.cn/problems/maximum-number-of-robots-within-budget/ 你有 n 个机器人&#xff0c;给你两个下标从 0 开始的整数数组 chargeTimes …...

vue 在线预览word和excel

yarn add vue-office/excel vue-office/docx <template><div><vue-office-docx:src"docx"style"height: 100%; margin: 0; padding: 0"rendered"rendered"/></div> </template><script> //引入VueOfficeDoc…...

物联网智能项目

物联网智能项目是一个涉及多个领域和技术的综合性项目&#xff0c;旨在通过互联网将各种物理设备连接起来&#xff0c;实现数据的采集、传输、处理和分析&#xff0c;进而实现智能化控制和管理。以下是对物联网智能项目的详细阐述&#xff0c;包括其定义、关键技术、应用领域、…...

828华为云征文|Flexus云服务器X:Python安装的极致便捷之旅

目录 前言 一、Flexus云服务器X介绍 1.1 Flexus云服务器X实例简介 1.2 Flexus云服务器X实例特点 1.3 Flexus云服务器X实例场景需求 二、Flexus云服务器X购买 2.1 Flexus X实例购买 2.2 重置密码 2.3 登录服务器 三、Flexus云服务器X安装Python 3.1 Python下载 3.2 Python安装 3…...

Midjourney中秋特典-12张图附魔咒

第一张 魔咒 A Mid-Autumn Festival poster, a round bright moon, a Chinese-style pavilion with a scene of a reunion from Dream of the Red Chamber, a new Chinese style --ar 3:4 --v 6.1第二张 魔咒 The bright full moon hung in the night sky,clear in outline a…...

编写程序,从键盘输入若干整数,将其保存入一个数组中。利用Arravs进行排序,然后查找出第3大的整数

编写程序&#xff0c;从键盘输入若干整数&#xff0c;将其保存入一个数组中。利用Arravs进行排序&#xff0c;然 后查找出第3大的整数 import java.util.ArrayList; import java.util.Arrays; import java.util.Scanner;public class helloworld {public static void main(Stri…...

VSCode 离线安装中文语言包

1.插件市场 Extensions for Visual Studio family of products | Visual Studio Marketplace 输入&#xff1a; language 在version history里面下载相应的版本&#xff0c;若没有就下载最新的 在下面安装 安装完重启就可以了。 可能会提示的失败&#xff1a; Unable to ins…...

vue3补充

form表单重置 const { proxy } getCurrentInstance()!; // 获取挂载在全局的上下文proxy.resetForm(ruleFormRef); // 在el-form中清空ref为ruleFormRef的表单注&#xff1a;不推荐使用 不推荐的原因 类型安全问题&#xff1a; 当在 TypeScript 环境中使用时&#xff0c;…...

关于Chrome浏览器没有网络,而其他浏览器正常这一问题的解决方法

网上有很多解决方案&#xff0c;但我尝试了之后都没有效果。后来尝试开启了VPN&#xff0c;问题完美解决了。 ✿✿ヽ(▽)ノ✿ 解决前&#xff1a;打开VPN后很容易就解决了&#xff1a;...

人工智能辅助汽车造型设计

随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域的应用越来越广泛&#xff0c;汽车设计行业也不例外。尤其在车辆外观造型设计中&#xff0c;AI正在成为设计师的重要助手&#xff0c;通过提供强大的工具和独特的创意方式&#xff0c;革新了传统设…...

专家访谈:心脑血管名医蔡英丽医生的医学智慧

在心脑血管疾病的诊疗领域&#xff0c;有这样一位医生&#xff0c;她以深厚的医学功底、精湛的医术和无私的爱心&#xff0c;赢得了广大患者的信赖与赞誉。她&#xff0c;就是北京心脑血管科的蔡英丽医生。今天&#xff0c;我们将带您走进蔡英丽医生的医学世界&#xff0c;一探…...

Ubuntu 22.04 源码下载的几种方法

1、查询当前系统内核版本 rootubuntu22:~# uname -r 5.15.0-118-generic 2、查询本地软件包数据库中的内核源码信息 rootubuntu22:~# apt search linux-source Sorting... Done Full Text Search... Done linux-source/jammy-updates,jammy-security,now 5.15.0.119.119 all…...

floodfill+DFS(1)

文章目录 图像渲染岛屿数量岛屿的最大面积被围绕的岛屿 图像渲染 class Solution { public:int m 0, n 0;bool check[51][51] {false};vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {m image.size…...

小程序开发设计-第一个小程序:注册小程序开发账号②

上一篇文章导航&#xff1a; 小程序开发设计-小程序简介①-CSDN博客https://blog.csdn.net/qq_60872637/article/details/142217803?sharetypeblogdetail&sharerId142217803&sharereferPC&sharesourceqq_60872637&spm1011.2480.3001.8118 须知&#xff1a;不…...

C++基础面试题 | C++中的构造函数可以是虚函数吗? C++中的析构函数一定要是虚函数吗?

文章目录 问题一&#xff1a;在C中&#xff0c;构造函数不能是虚函数。问题二&#xff1a;析构函数不一定需要声明为虚函数&#xff0c;但在多态环境下&#xff0c;建议一定将其声明为虚函数。示例虚函数总结 问题一&#xff1a;在C中&#xff0c;构造函数不能是虚函数。 这是…...

无机布防火卷帘门价格怎么算?按尺寸定制,按需报价

无机布防火卷帘门作为建筑防火分区的核心设备&#xff0c;价格一直是工程采购的关注重点。很多用户在询价时&#xff0c;会发现不同厂家的报价差异较大&#xff0c;这是因为无机布防火卷帘门的价格并非按统一单价计算&#xff0c;而是完全根据项目的实际需求定制化核算。 &…...

环境光遮蔽(Ambient Occlusion):揭秘那个让虚拟世界“有重量感“的阴影魔法

一、一个让我"开窍"的老木匠故事 我有个朋友是传统家具的修复师&#xff0c;他给我讲过一个让我至今难忘的故事。他说他刚入行时跟着一位 70 多岁的老木匠师父学习——师父让他做的第一件事不是雕花、不是榫卯——而是"看阴影"——这个看似奇怪的训练改变了…...

App Inventor蓝牙调试避坑指南:从连接失败到数据乱码,一次讲清所有常见问题

App Inventor蓝牙调试避坑指南&#xff1a;从连接失败到数据乱码的实战解决方案在移动应用开发领域&#xff0c;蓝牙通信一直是实现设备间短距离数据交换的核心技术之一。对于使用App Inventor的开发者而言&#xff0c;蓝牙模块提供了无需复杂编码即可实现无线通信的便捷途径。…...

从多路复用到三维光阵:Arduino驱动8x8x8 LED立方体全解析

1. 项目概述&#xff1a;用Arduino点亮一个三维世界几年前&#xff0c;我第一次在创客展上看到一个8x8x8的LED立方体&#xff0c;那种由数百个光点构成的、在三维空间中流动的动画效果&#xff0c;瞬间就把我吸引住了。它不像普通的平面LED屏&#xff0c;而是真正有“深度”的光…...

【DeepSeek开源协议识别权威指南】:20年合规专家亲授3大协议陷阱与5步精准识别法

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek开源协议识别的底层逻辑与合规价值 DeepSeek系列模型&#xff08;如DeepSeek-V2、DeepSeek-Coder&#xff09;虽以“开源”名义发布&#xff0c;但其实际许可状态需通过结构化协议解析才能准确…...

AI开始替人办事后,最危险的不是模型不够强,而是它把旧资料当真了

AI开始替人办事后&#xff0c;最危险的不是模型不够强&#xff0c;而是它把旧资料当真了2026年真正值得重视的AI底层能力&#xff0c;是让模型知道该信谁 你有没有发现一个很扎心的变化。 以前我们用AI&#xff0c;最怕它不会。 现在我们用AI&#xff0c;最怕它太会了。 它能写…...

LeagueAkari:英雄联盟终极自动化助手革命性指南

LeagueAkari&#xff1a;英雄联盟终极自动化助手革命性指南 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 你是否在英雄联盟游戏中反复经历这…...

自然语言处理的实战项目:从0到1搭建属于自己的文本分类系统

对于软件测试从业者而言&#xff0c;日常工作中我们每天都会接触大量的文本数据&#xff1a;缺陷管理系统中的bug描述、测试用例的步骤说明、用户反馈的问题报告、需求文档的规格描述&#xff0c;甚至是接口返回的异常信息文本。这些非结构化文本往往隐含着关键业务信息&#x…...

对比直接调用厂商API使用Taotoken聚合调用的延迟体感差异

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 对比直接调用厂商API使用Taotoken聚合调用的延迟体感差异 在将应用从直接调用单一厂商的模型API迁移到Taotoken平台后&#xff0c;…...

3步解决英雄联盟回放难题:ROFL-Player终极使用指南

3步解决英雄联盟回放难题&#xff1a;ROFL-Player终极使用指南 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 你是否曾经遇到过这样的烦…...