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

news2024/11/27 5:23:21

文章目录

  • 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 秒。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据-159 Apache Kylin 构建Cube 准备和测试数据

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

AI会计师——让AI+成就价值财务

摘要&#xff1a;用友携手CCTV-10联合策划《AI会计师》专题节目 目录 Part1 数智化凭证采集 Part2 智能月结 Part3 税务风险管控 Part1 数智化凭证采集 AI会计师&#xff0c;源自对大数据、人工智能、云计算等前沿技术的深度融合。它不仅仅是一款软件&#xff0c;更是企业智能…

Java 17 数组最全解读篇(3w字图文并茂)

小熊学Java&#xff1a;https://www.javaxiaobear.cn&#xff0c;包含了海量的面试题和Java学习资料&#xff0c;是一个全能学习的站点&#xff0c;强烈推荐&#xff01;&#xff01;&#xff01; 1. 数组的概述 1.1 为什么需要数组 需求分析1&#xff1a; 需要统计某公司50…

探索远程控制下载工具的奇妙世界

远程控制技术为我们的生活和工作带来了极大的便利。比如协助他人解决电脑问题、远程办公等等。今天我们一同来探讨向日葵远程控制下载软件和其他远程控制软件的奇妙世界。 1.向日葵远程控制 链接直通车&#xff1a;https://down.oray.com 想必很多人都听说过这款软件的卓越声…

如何用AI两小时上线自己的小程序

ChatGPT这个轰动全球的产品自问世以来&#xff0c;已经过了将近2年的时间&#xff0c;各行各业的精英们如火如荼的将AI能力应用到自己生产的产品中来。 为分担人类的部分工作&#xff0c;AI还具有非常大的想象空间&#xff0c;例如对于一个程序员来说&#xff0c;使用AI生成快…

2024 全新视角:MBTI 报告 API 接口登场

MBTI&#xff08;Myers-Briggs Type Indicator&#xff09;是一种常用的心理学测量工具&#xff0c;通过分析个体在四个维度上的偏好&#xff0c;将人们分为16种不同的人格类型。随着人工智能和数据科学的快速发展&#xff0c;现在我们有了全新的方式来获取和分析MBTI报告&…

[考研数学]多元函数,向量函数,向量场辨析

参考视频&#xff1a;【【高等数学】多元函数&#xff0c;向量函数&#xff0c;向量场这些概念你能分得清吗&#xff1f;】 首先这几个都是映射 我们求的梯度就是多元函数里面的概念。 我们求的散度和旋度是向量场里面的概念。 多元函数多维到一维的意思是比如说输入一个点&am…

ChatGPT可以分析股票吗?

结合国庆前大A股市的小波牛市以及今天的股市表现&#xff0c;我从多个角度为你提供一些分析和建议&#xff1a; 一、国庆前的小波牛市分析 国庆前&#xff0c;大A股市出现了一波小幅上涨&#xff0c;市场呈现出一些积极的信号&#xff1a; 政策面利好&#xff1a;政府出台了…

A股知识答题pk小程序怎么做?

A股知识答题pk小程序怎么做&#xff1f;以下是制作A股知识答题PK小程序的一般步骤&#xff1a; 一、 需求分析与规划&#xff1a; 明确目标&#xff1a;确定小程序的主要目标&#xff0c;比如是为了帮助用户学习A股知识、进行趣味竞赛&#xff0c;还是作为金融教育工具等。 …

Python 如何使用 SQLAlchemy 进行复杂查询

Python 如何使用 SQLAlchemy 进行复杂查询 一、引言 SQLAlchemy 是 Python 生态系统中非常流行的数据库处理库&#xff0c;它提供了一种高效、简洁的方式与数据库进行交互。SQLAlchemy 是一个功能强大的数据库工具&#xff0c;支持结构化查询语言&#xff08;SQL&#xff09;…

Otter Wiki:用 Python 和 Markdown 搭建你的小型知识库,三步搞定!

你有没有想过,有没有一种工具可以轻松管理你的个人知识库,还不用费力学习复杂的操作系统?今天,我们来聊聊 Otter Wiki,一个由 Python、Markdown 和 Git 支撑的小型 Wiki 系统,让你能快速构建属于自己的知识管理工具,完全不需要依赖庞大的平台。 为什么选择 Otter Wi…

《向量数据库指南》深度解读:CLIP模型架构与Mlivus Cloud的向量数据库应用实践

在当今这个数据驱动的时代,向量数据库以其高效、灵活的特性,在AI应用、大数据处理等领域发挥着越来越重要的作用。作为大禹智库的向量数据库高级研究员,同时也是《向量数据库指南》的作者,我深知向量数据库技术的核心价值和未来发展潜力。今天,我们将一起深入探讨CLIP模型…

鸟哥的linux私房菜-基础篇-第四版

第六章 文件与目录 6.1 目录与路径 6.1.2 目录的相关操作 cd&#xff1a;变换目录pwd&#xff1a;显示当前目录mkdir&#xff1a;建立一个新的目录rmdir&#xff1a;删除一个空的目录 cd dmtsai 这个用户的家目录是/home/dmtsai/&#xff0c;而 root 家目录则是/root/&…

LEAP模型的低碳路径建模与温室气体核算方法!详细

LEAP 模型&#xff08;Long-range Energy Alternatives Planning System&#xff09;&#xff0c;即低排放分析系统&#xff0c;是一个基于情景分析的自底向上的能源—环境核算工具&#xff0c;由斯德哥尔摩环境研究所与美国波士顿大学共同开发。LEAP拥有灵活的结构&#xff0c…

算法笔记(十五)——BFS 解决拓扑排序

文章目录 拓扑排序课程表课程表 II火星词典 拓扑排序 有向无环图&#xff08;DAG图&#xff09; 有向无环图指的是一个无回路的有向图 AOV网&#xff1a;顶点活动图 在有向无环图中&#xff0c;用顶点表示一个活动&#xff0c;用边来表示活动的先后顺序的图结构 拓扑排序 找到一…

鸿蒙HarmonyOS中Image图片组件以及HarmonyOs图标库完全解析

Image 图片组件&#xff0c;支持本地图片和网络图片的渲染展示。 一 、加载网络图片 1 、需要在 src/main/module.json5 中申请网络权限 "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] 详情参考&#xff1a; https://d…

展览会:企业宣传和推广的重要平台之一

在当今这个信息爆炸、市场竞争日益激烈的时代&#xff0c;展会作为企业与市场直接对话的重要桥梁&#xff0c;其推广的重要性愈发凸显。展会不仅是产品展示、技术交流的平台&#xff0c;更是品牌塑造、市场拓展的关键一环。 一、提升品牌知名度与形象 展会是企业向外界展示自…

新一届诺贝尔奖揭晓,能否为医学AI领域带来一些启发?|个人观点·24-10-09

小罗碎碎念 还未从microRNA的知识海洋中抽身出来&#xff0c;又要面对受限玻尔兹曼机带来的冲击。 这两天随着诺贝尔奖的公布&#xff0c;学术界可谓是热闹非凡&#xff0c;我也正好趁着这个机会&#xff0c;拾起停更半个月的公众号。 作为医学人工智能研究大军中的一员&#…

各省财政涉农支出统计(2001-2022年)

财政涉农支出是指政府预算中用于支持农业、农村和农民发展的财政支出&#xff0c;旨在促进农村经济的发展&#xff0c;提高农民收入&#xff0c;改善农村生产生活条件&#xff0c;推进农业现代化。 2001年-2022年各省财政涉农支出统计&#xff08;数据整理&#xff09;.zip资源…

Linux平台Kafka高可用集群部署全攻略

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《大数据前沿&#xff1a;技术与应用并进》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Kafka简介 2、Kafka核心优势 二、环境准备 1…