【C++网络编程】(一)Linux平台下TCP客户/服务端程序

文章目录

  • Linux平台下TCP客户/服务端程序
    • 服务端
    • 客户端
    • 相关头文件介绍

Linux平台下TCP客户/服务端程序


图片来源:https://subingwen.cn/linux/socket/

下面实现一个Linux平台下TCP客户/服务端程序:客户端向服务器发送:“你好,服务器…递增数字”,然后服务器发送响应消息:“你好,客户端”。
在这里插入图片描述

服务端

server.cpp

#include <iostream>    
#include <cstdlib>      // std::exit
#include <cstring>      // memset sprintf strlen
#include <arpa/inet.h>  // inet_ntop, htons, ntohs, INADDR_ANY, INET_ADDRSTRLEN 
#include <unistd.h>     // close
// #include <sys/socket.h> // sockaddr_in,  socket(),  bind(), listen(), accept(), send(), recv(),SOCK_STREAM,AF_INET
/*
<arpa/inet.h>包含了<netinet/in.h>,而<netinet/in.h>包含了 <sys/socket.h>。
所以实际使用时,只需要#include <arpa/inet.h>,不需要#include <sys/socket.h> 
*/


int main()
{
      // 1. 创建监听的套接字
      int lfd = socket(AF_INET, SOCK_STREAM, 0);  // 创建一个TCP套接字
      if (lfd == -1)
      {
            perror("socket");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 2. 将socket()返回值和本地的IP端口绑定到一起
      sockaddr_in addr;  // 用于存储地址信息
      addr.sin_family = AF_INET; // 地址族,IPv4
      addr.sin_port = htons(10000);   // 大端端口转换
      //addr.sin_addr.s_addr = INADDR_ANY;  // 绑定到任意IP地址
      inet_pton(AF_INET, "172.31.108.107", &addr.sin_addr.s_addr); // 指定IP地址

      int ret = bind(lfd, (sockaddr*)&addr, sizeof(addr)); // 绑定套接字到地址
      if (ret == -1)
      {
            perror("bind");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 3. 设置监听
      ret = listen(lfd, 128);  // 开始监听
      if (ret == -1)
      {
            perror("listen");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 4. 阻塞等待并接受客户端连接
      sockaddr_in cliaddr; // 用于存储客户端地址信息
      socklen_t clilen = sizeof(cliaddr);  // 客户端地址结构的大小
      int cfd = accept(lfd, (sockaddr*)&cliaddr, &clilen); // 接受客户端连接
      if (cfd == -1)
      {
            perror("accept");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 打印客户端的地址信息
      char ip[INET_ADDRSTRLEN] = {0};  // 存储客户端IP地址
      std::cout << "客户端的IP地址: " 
                  << inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip))  // 将IP地址转换为字符串
                  << ", 端口: " 
                  << ntohs(cliaddr.sin_port) << std::endl;  // 端口号转换

      // 5. 和客户端通信
      while (true)
      {
            // 接收数据
            char buf[1024];  // 接收缓冲区
            memset(buf, 0, sizeof(buf));  // 清零缓冲区
            int len = recv(cfd, buf, sizeof(buf), 0);  // 从客户端读取数据
            if (len > 0)
            {
	            std::cout << "客户端: " << buf << std::endl;  // 打印客户端发送的消息
	
	            sprintf(buf, "你好, 客户端\n");  // 格式化字符串
	            send(cfd, buf, strlen(buf), 0);  // 回应客户端
            }
            else if (len == 0)
            {
	            std::cout << "客户端断开了连接..." << std::endl;  // 客户端断开连接
	            break;
            }
            else
            {
	            perror("recv");  // 错误处理
	            break;
            }
      }

      close(cfd);  // 关闭与客户端的连接
      close(lfd);  // 关闭监听套接字

      return 0;
}

编译与运行

g++ server.cpp -o server
./server

客户端

client.cpp

#include <iostream>     // std::cout, std::cerr
#include <cstdlib>     // std::exit
#include <unistd.h>     // close, sleep
#include <cstring>      // memset, strlen
#include <arpa/inet.h>  // socket, connect, inet_pton, htons

int main()
{
      // 1. 创建通信的套接字
      int fd = socket(AF_INET, SOCK_STREAM, 0);  // 创建一个TCP套接字
      if (fd == -1)
      {
            perror("socket");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 2. 连接服务器
      sockaddr_in addr;  // 用于存储服务器地址信息
      addr.sin_family = AF_INET; // 地址族,IPv4
      addr.sin_port = htons(10000);   // 大端端口转换
      inet_pton(AF_INET, "172.31.108.107", &addr.sin_addr.s_addr); // 将IP地址转换为网络字节顺序

      int ret = connect(fd, (sockaddr*)&addr, sizeof(addr)); // 连接到服务器
      if (ret == -1)
      {
            perror("connect");  // 错误处理
            std::exit(EXIT_FAILURE);
      }

      // 3. 和服务器端通信
      int number = 0;
      while (true)
      {
            // 发送数据
            char buf[1024];  // 数据缓冲区
            sprintf(buf, "你好, 服务器...%d", number++);  // 格式化字符串
            send(fd, buf, strlen(buf), 0);  // 发送数据
            
            // 接收数据
            memset(buf, 0, sizeof(buf));  // 清空缓冲区
            int len = recv(fd, buf, sizeof(buf), 0);  // 从服务器读取数据
            if (len > 0)
            {
                  std::cout << "服务器: " << buf;  // 打印服务器发送的消息
            }
            else if (len == 0)
            {
                  std::cout << "服务器断开了连接..." << std::endl;  // 服务器断开连接
                  break;
            }
            else
            {
                  perror("recv");  // 错误处理
                  break;
            }
            sleep(1);   // 每隔1秒发送一条数据
      }

      close(fd);  // 关闭套接字

      return 0;
}

编译与运行

g++ client.cpp -o client
./client

相关头文件介绍

  1. <cstdlib> :提供了一些常用的标准库函数,源自 C 的 stdlib.h,这些函数与程序控制、内存分配、随机数生成等功能相关。使用到的函数:

    • std::exit(int status):终止程序执行,status 用来返回退出状态码,0 表示正常退出,非 0 表示异常退出。 无返回值,直接终止程序。
  2. <cstring>:是对 C 语言 string.h 的封装,提供了用于操作 C 风格字符串(以 '\0' 结尾的字符数组)和内存操作的函数。使用到的函数:

    • ptr = memset(void* ptr, int value, size_t num):将指定内存区域的前 num 个字节设置为 value。 返回指向 ptr 的指针,即被修改的内存区域的起始地址。
    • n = sprintf(char* buffer, const char* format, ...):将格式化数据写入 buffer,并返回写入的字符数。返回写入 buffer 中的字符数(不包括终止符 '\0')。
    • len = strlen(const char* str):返回 C 风格字符串 str 的长度(不包括终止符 '\0')。 返回 str 的长度。
  3. <arpa/inet.h>:提供了一些用于网络编程的工具函数,主要用于 IP 地址与主机字节序、网络字节序的转换。使用到的函数和宏:

    • inet_ntop(int af, const void* src, char* dst, socklen_t size):将网络格式(大端序)的二进制 IP 地址转换为可读的点分十进制或冒号分隔的字符串。
    • inet_pton(int af, const char* src, void* dst):将可读的点分十进制或冒号分隔的字符串格式的 IP 地址转换为网络格式(大端序)的二进制格式。
    • netshort = htons(uint16_t hostshort):将主机字节序(小端序)的 16 位数转换为网络字节序(大端序)。 返回转换后的网络字节序的 16 位数。
    • hostshort = ntohs(uint16_t netshort):将网络字节序的 16 位数转换为主机字节序。 返回转换后的主机字节序的 16 位数。
    • INADDR_ANY:用于表示绑定到所有可用的本地接口(IP 地址为 0.0.0.0)。
    • INET_ADDRSTRLEN 是一个常量,表示用于存储 IPv4 地址的字符串格式的最大长度。其值通常为 16,这是因为 IPv4 地址的最坏情况是点分十进制表示的字符串形式,如 “255.255.255.255”,该字符串的长度为 15,加上一个字符串终止符 ‘\0’,总共为 16。
  4. <sys/socket.h>:提供了与套接字编程相关的函数和数据结构,定义了套接字的创建、绑定、监听、接受连接、数据收发等功能。使用到的函数、宏和结构体:

    • sockfd = socket(int domain, int type, int protocol):创建一个套接字,domain 表示协议族(如 IPv4 , IPv6),type 表示套接字类型(如 SOCK_STREAM 表示 TCP),protocol 通常为 0,表示默认协议。 返回新的套接字描述符,失败时返回 -1
    • result = bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen):将套接字绑定到特定地址(IP 和端口)。 返回 0 表示成功,返回 -1 表示出错。
    • result = listen(int sockfd, int backlog):将套接字设置为监听模式,backlog 表示队列中可以等待的最大连接数。 返回 0 表示成功,返回 -1 表示出错。
    • new_sockfd = accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen):接受连接请求,并返回一个新的套接字,失败时返回 -1
    • bytes_sent = send(int sockfd, const void* buf, size_t len, int flags):通过连接的套接字发送数据。 返回成功发送的字节数,失败时返回 -1
    • bytes_received = recv(int sockfd, void* buf, size_t len, int flags):从连接的套接字接收数据。 返回成功接收的字节数,返回 0 表示对方关闭连接,失败时返回 -1
    • AF_INET: 是一个常量,用于指定地址族,表示使用 IPv4 地址。
    • SOCK_STREAM:是一个常量,用于指定套接字类型,表示该套接字将使用 TCP 协议进行流式数据传输。
    • sockaddr_in:专门用于 IPv4 地址的结构体,包含 sin_family(地址族)、sin_port(端口号)、sin_addr(IP 地址)等字段。
      struct sockaddr_in {
          short int          sin_family;   // 地址族
          unsigned short int sin_port;     // 端口号 (网络字节序)
          struct in_addr     sin_addr;     // IP 地址
          unsigned char      sin_zero[8];  // 填充字段(未使用)
      };
      
  5. <unistd.h>:是 Unix-like 操作系统的头文件,提供了对系统调用的访问接口,包含文件操作、进程管理等低级功能。使用到的函数:

    • result = close(int fd):关闭文件描述符 fd,在网络编程中用于关闭套接字。 返回 0 表示成功,返回 -1 表示出错。
    • sleep(unsigned int seconds) :暂停执行当前线程 seconds 秒。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891094.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络资源模板--Android Studio 实现简易新闻App

目录 一、项目演示 二、项目测试环境 三、项目详情 四、完整的项目源码 一、项目演示 网络资源模板--基于Android studio 实现的简易新闻App 二、项目测试环境 三、项目详情 登录页 用户输入&#xff1a; 提供账号和密码输入框&#xff0c;用户可以输入登录信息。支持“记…

[ComfyUI]Flux:国漫经典!斗破苍穹古熏儿之绮梦流光模型来袭

在数字艺术和创意领域&#xff0c;FLUX以其独特的虚实结合技术&#xff0c;已经成为艺术家和设计师们手中的利器。今天&#xff0c;我们激动地宣布&#xff0c;FLUX推出了一款全新的ComfyUI版本——Flux&#xff0c;它将国漫经典《斗破苍穹》中的古熏儿之绮梦流光模型完美融合&…

第十四章 RabbitMQ延迟消息之延迟队列

目录 一、引言 二、死信队列 三、核心代码实现 四、运行效果 五、总结 一、引言 什么是延迟消息&#xff1f; 发送者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间后收到消息。 什么是延迟任务&#xff1f; 设置在一定时间之后才…

Qt入门教程:创建我的第一个小程序

本章教程&#xff0c;主要介绍如何编写一个简单的QT小程序。主要是介绍创建项目的过程。 一、打开QT软件编辑器 这里使用的是QT5.14.2版本的&#xff0c;安装教程参考以往教程&#xff1a;https://blog.csdn.net/qq_19309473/article/details/142907096 二、创建项目 到这里&am…

使用Docker部署nextjs应用

最近使用nextjs网站开发&#xff0c;希望使用docker进行生产环境的部署&#xff0c;减少环境的依赖可重复部署操作。我采用的是Dockerfile编写应用镜像方式 docker-compose实现容器部署的功能。 Docker Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器…

【大模型问答测试】大模型问答测试脚本实现(第一版)

背景 公司已经做了一段时间的大模型&#xff0c;每次测试或者回归的时候都需要针对问答进行测试回归&#xff0c;耗费大量的时间与精力&#xff0c;因此结合产品特点&#xff0c;开发自动化脚本替代人工的操作&#xff0c;提升测试回归效率 设计 使用pythonrequestExcel进行…

Android笔记(二十四)基于Compose组件的MVVM模式和MVI模式的实现

仔细研究了一下MVI(Model-View-Intent)模式&#xff0c;发现它和MVVM模式非常的相识。在采用Android JetPack Compose组件下&#xff0c;MVI模式的实现和MVVM模式的实现非常的类似&#xff0c;都需要借助ViewModel实现业务逻辑和视图数据和状态的传递。在这篇文章中&#xff0c…

易我数据恢复软件,一键找回你的重要资料!

我们生活在数字时代&#xff0c;数据对我们来说超级重要。工作文件、学习资料&#xff0c;还有照片视频&#xff0c;这些东西要是没了或者不小心删了&#xff0c;那得多烦人啊。幸好现在科技发达&#xff0c;有了数据恢复软件&#xff0c;就像给我们数据上了一把安全锁。市面上…

一篇闪击常用放大器电路(学习笔记)

文章目录 声明概念名词经典电路分析反向放大器同向放大器加法器减法器积分电路微分电路差分放大电路电流->电压转换电路电压->电流转换电路 虚短与虚断一、虚短二、虚断 一些碎碎念 声明 ​ 本文是主要基于以下两篇博客所做的笔记&#xff1a; 模电四&#xff1a;基本放…

IT招聘乱象的全面分析

近年来&#xff0c;IT行业的招聘要求似乎越来越苛刻&#xff0c;甚至有些不切实际。许多企业在招聘时&#xff0c;不仅要求前端工程师具备UI设计能力&#xff0c;还希望后端工程师精通K8S服务器运维&#xff0c;更有甚至希望研发经理掌握所有前后端框架和最新开发技术。这种招聘…

MySQL基本语法、高级语法知识总结以及常用语法案例

MySQL基本语法总结 MySQL是一种广泛使用的关系型数据库管理系统&#xff0c;其基本语法涵盖了数据库和数据表的创建、查询、修改和删除等操作。 一、数据库操作 创建数据库&#xff08;CREATE DATABASE&#xff09; 语法&#xff1a;CREATE DATABASE [IF NOT EXISTS] databa…

最新PHP礼品卡回收商城 点卡回收系统源码_附教程

最新PHP礼品卡回收商城 点卡回收系统源码_附教程 各大电商平台优惠券秒杀拼团限时折扣回收商城带余额宝 1、余额宝理财 2、回收、提现、充值、新订单语音消息提醒功能 3、带在线客服 4、优惠券回收功能 源码下载&#xff1a;https://download.csdn.net/download/m0_66047…

Android实现App内直接预览本地PDF文件

在App内实现直接预览pdf文件&#xff0c;而不是通过调用第三方软件&#xff0c;如WPS office等打开pdf。 主要思路&#xff1a;通过PhotoView将pdf读取为图片流进行展示。 一、首先&#xff0c;获取对本地文件读取的权限 在AndrooidManifest.xml中声明权限&#xff0c;以及页…

Windows,MySQL主从复制搭建

前提&#xff1a;windows环境&#xff0c;同一个服务器安装多个相同版本的mysql数据库 多个MySQL服务搭建完成后&#xff0c;下面我们进行主从复制的相关配置 1.主数据库 执行指令 #创建用户 CREATE USER slavelocalhost IDENTIFIED BY 123456;#授权 GRANT REPLICATION SLA…

[CS报错]找不到 .NETFramework,Version=v4.6.2 的引用程序集

报错 error MSB3644: 找不到 .NETFramework,Versionv4.6.2 的引用程序集。要解决此问题&#xff0c;请为此框架版本安装开发人员工具包(SDK/目标包)或者重新定向应用程序。可在 https://aka.ms/msbuild/developerpacks 处下载 .NET Framework 开发人员工具包 解决 打开https…

【计网】从零开始理解UDP协议 --- 理解端口号和UDP结构

我依旧敢和生活顶撞&#xff0c; 敢在逆境里撒野&#xff0c; 直面生活的污水&#xff0c; 永远乐意为新一轮的月亮和日落欢呼。 --- 央视文案 --- 从零开始理解UDP协议 1 再谈端口号2 理解UDP 报头结构3 UDP 的特点4 UDP 的缓冲区5 UDP 使用注意事项 1 再谈端口号 之前我…

pycharm里debug时如何看到数据的维度

使用表达式计算&#xff08;Evaluate Expression&#xff09; 调试时&#xff0c;使用 PyCharm 的 “Evaluate Expression” 功能可以动态查看或修改数据。具体步骤如下&#xff1a; 在调试模式中按 Alt F8&#xff08;Windows&#xff09;或 Option F8&#xff08;Mac&…

Cortex-A7:如何切换ARM和Thumb状态

0 参考资料 ARM Cortex-A(armV7)编程手册V4.0.pdf1 Cortex-A7&#xff1a;如何切换ARM和Thumb状态 1.1 Cortex-A7支持的指令集 Cortex-A7支持的指令集包括ARM指令集和Thumb-2&#xff08;ARM官方一般用Thumb表示&#xff09;指令集。 ARM指令集指令大小都是32位&#xff0c;…

2024 年 04 月编程语言排行榜,PHP 排名创新低?

编程语言的流行度总是变化莫测&#xff0c;每个月的排行榜都揭示着新的趋势。2024年4月的编程语言排行榜揭示了一个引人关注的现象&#xff1a;PHP的排名再次下滑&#xff0c;创下了历史新低。这种变化对于PHP开发者和整个技术社区来说&#xff0c;意味着什么呢&#xff1f; P…

第十一章 RabbitMQ之消费者确认机制

目录 一、介绍 二、演示三种ACK方式效果 2.1. none: 不处理 2.1.1. 消费者配置代码 2.1.2. 生产者主要代码 2.1.3. 消费者主要代码 2.1.4. 运行效果 2.2. manual&#xff1a;手动模式 2.3. auto&#xff1a;自动模式 一、介绍 消费者确认机制&#xff08;Consume…