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

【C++】网络编程之Socket初体验-超详细!

目录

    • 1:Socket(套接字)之初步了解
      • 1.1套接字的概念
      • 1.2套接字的类型
      • 1.3套接字的声明周期
      • 1.4套接字的编程流程
        • 1.4.1服务器端:
        • 1.4.2客户端:
      • 1.5套接字编程的API
      • 1.6套接字编程的注意事项
    • 2.套接字编程之初体验
      • 2.1:服务端(server.cpp)
      • 2.2客户端(client.cpp)
    • 3.测试
    • 4.简易流程图

1:Socket(套接字)之初步了解

套接字(Socket)是网络编程中一个非常基本的概念,它是网络通信过程中端点的抽象表示,允许程序之间的数据交换。在计算机网络中,套接字用于实现不同主机上的进程通信。

1.1套接字的概念

套接字是一种通信机制,它为进程间的通信提供了一个端点。在网络中,每个进程都可以通过一个唯一的地址来识别,这个地址由IP地址和端口号组成。因此,一个套接字通常由以下三部分组成:
协议族(通常为AF_INET,表示IPv4)
端口号(一个16位的数字,用于区分同一主机上运行的不同服务)
IP地址(用于标识主机)

1.2套接字的类型

套接字主要有两种类型:
流套接字(SOCK_STREAM):提供顺序、可靠、双向连接的字节流。流套接字使用传输控制协议(TCP)作为传输层协议,确保数据的可靠传输。
数据报套接字(SOCK_DGRAM):提供无连接的服务,数据以数据报的形式发送。每个数据报都是独立的,不保证顺序和可靠性。数据报套接字使用用户数据报协议(UDP)作为传输层协议。

1.3套接字的声明周期

一个套接字的生命周期通常包括以下几个步骤:
创建:使用socket()函数创建一个新的套接字。
绑定:使用bind()函数将套接字与一个地址和端口绑定,这样它就可以开始监听或接收数据。
监听(仅对服务器):服务器使用listen()函数监听来自客户端的连接请求。
接受(仅对服务器):服务器使用accept()函数接受客户端的连接请求,创建一个新的套接字用于与客户端通信。
连接(仅对客户端):客户端使用connect()函数发起对服务器的连接请求。
数据传输:使用send()和recv()(或read()和write())函数在客户端和服务器之间传输数据。
关闭:使用close()函数关闭套接字,释放资源。

1.4套接字的编程流程

1.4.1服务器端:

创建套接字。
绑定套接字到一个地址和端口。
监听端口上的连接请求。
接受客户端的连接请求。
使用接受的套接字进行数据传输。
关闭套接字。

1.4.2客户端:

创建套接字。
连接到服务器的地址和端口。
使用连接的套接字进行数据传输。
关闭套接字。

1.5套接字编程的API

在C和C++中,套接字编程通常使用以下系统调用:
socket():创建一个新的套接字。
bind():将套接字绑定到特定的IP地址和端口。
listen():使套接字进入监听状态,等待连接请求。
accept():接受一个连接请求,创建一个新的套接字用于通信。
connect():发起一个连接请求到服务器。
send() 和 recv():发送和接收数据。
close():关闭套接字。

1.6套接字编程的注意事项

错误处理:网络编程中,错误处理非常重要。每个系统调用都可能失败,需要检查返回值并适当处理错误。
异步处理:网络操作可能是异步的,需要考虑如何处理阻塞和非阻塞操作。
安全性:网络通信可能面临安全威胁,需要考虑加密和验证机制。

2.套接字编程之初体验

准备:这里我只用了一台Ubuntu虚拟机,Xshell(开两个窗口,一个服务器,一个客户端),VSCode(比较喜欢用VSCode连虚拟机写代码,直接Vim也行)。OK,开工!

2.1:服务端(server.cpp)

这里所有的解释就都写在注释了,应该算是写得详细了!

#include <iostream> 
#include <cstring>
#include <sys/socket.h>  //包含socket函数和数据结构
#include <netinet/in.h>  //包含Internet地址簇
#include <unistd.h>     //包含标准符号常数和类型using namespace std;
const int PORT=1202;int main(){int server_fd,new_socket;//定义套接字文件描述符/*server_fd表示服务器的文件描述符,在网络编程中,套接字(socket)通过文件描述符来操作,就像操作文件一样。new_socket表示新的连接套接字,当服务器接受客户端的连接请求时,它会创建一个新的套接字来处理这个连接,这个新的套接字通过 new_socket 变量来表示。*/struct sockaddr_in address;//定义地址结构体/*sockaddr_in 结构体是一个非常重要的数据结构,它用于存储网络地址信息。这个结构体是 sockaddr 结构体的一个特化版本,专门用于IPv4地址。在 <netinet/in.h> 头文件中定义*/int addrlen=sizeof(address);//地址长度char buffer[1024]={0};//定义缓冲区/*定义了一个大小为1024字节的字符数组,用于存储接收到的数据或将要发送的数据。{0} 初始化数组中的所有元素为0,这是一个常见的做法,用于确保缓冲区不包含任何随机数据。当然了,它还有:保证数据完整性,提高效率,数据格式化,防止数据丢失等功能,这里是简单示例,主要就是用于存储接收到的数据或将要发送的数据,就不做解释了,*/const char *message="在想丽宝啊!";//定义服务器发送的消息,使用 const 可以防止函数意外修改字符串内容。安全//创建套接字,用于在C++网络编程中创建一个TCP套接字的。if((server_fd=socket(AF_INET,SOCK_STREAM,0))==0){perror("socket failed");exit(EXIT_FAILURE);}/*socket() 是一个系统调用,用于创建一个新的套接字。它返回一个文件描述符,该文件描述符是用于后续套接字操作(如绑定、监听、连接等)的索引。AF_INET表示IPv4地址族,用于创建一个基于IPv4的套接字。SOCK_STREAM表示创建一个提供序列化、可靠、双向连接的字节流套接字,这通常用于TCP连接。传递0表示使用默认的协议,对于AF_INET和SOCK_STREAM,这意味着使用TCP协议。== 0检查server_fd是否为0,即检查套接字是否创建失败。perror()函数将打印出错误信息到标准错误流exit()函数用于终止当前程序,并返回一个状态码给操作系统。EXIT_FAILURE是一个宏,通常定义为非零值,表示程序异常终止
*///设置套接字选项,允许地址重用int opt=1;if(setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt))){perror("setsockopt");exit(EXIT_FAILURE);}/*opt这个变量用于表示套接字选项的状态,1 表示启用该选项。setsockopt() 是一个系统调用,用于设置套接字选项。它可以改变套接字的行为,例如如何接收数据或者如何处理特殊的网络条件。SOL_SOCKET是一个指定套接字选项级别的常量,表示这是针对套接字本身的选项,而不是针对某个特定协议的。SO_REUSEADDR 是一个套接字选项,允许套接字绑定到一个已经被使用(在TIME_WAIT状态)的本地地址和端口。SO_REUSEPORT 是一个扩展选项,允许多个套接字绑定到同一个端口,只要它们的地址不同。如果 setsockopt() 返回非零值,表示设置选项失败。*///绑定套接字到端口address.sin_family=AF_INET;//地址簇,address.sin_addr.s_addr=INADDR_ANY;//地址。INADDR_ANY表示接受任意IP的连接address.sin_port=htons(PORT);//端口号,htons函数将主机字节序转换为网络字节序/*这三段代码是设置服务器端套接字地址信息的一部分,它们配置了服务器将监听的协议族、IP地址和端口号sin_family 是 sockaddr_in 结构体的一个成员,它指定了地址族。设置 sin_family 为 AF_INET 表示服务器将使用 IPv4 协议。sin_addr 是 sockaddr_in 结构体的一个成员,它是一个 in_addr 结构体,用于存储 IPv4 地址。INADDR_ANY 是一个特殊的常量,当绑定套接字时使用。它告诉操作系统自动绑定到所有可用的网络接口的 IPv4 地址。sin_port 是 sockaddr_in 结构体的一个成员,用于指定端口号。htons() 函数是 "host to network short" 的缩写,它将一个短整型(16位)从主机字节序转换为网络字节序。*///绑定套接字if(bind(server_fd,(struct sockaddr *)&address,sizeof(address))<0){perror("bind failed");exit(EXIT_FAILURE);}/*bind() 是一个系统调用,用于将一个套接字(server_fd)绑定到指定的地址和端口上。(struct sockaddr *)&address将address变量的地址传递给bind()函数其他基本的东西都和上面提到过的大相径庭*///监听套接字if(listen(server_fd,3)<0){//监听,参数3表示最大连接数perror("listen");exit(EXIT_FAILURE);}/*listen() 是一个系统调用,用于告诉内核准备接受连接请求。这个函数将一个被动套接字(也称为监听套接字)转变为监听状态。参数 3 表示服务器将允许最多3个连接请求在队列中等待接受。*/cout<<"Listening on port"<<PORT<<endl;//接受客户端连接if((new_socket=accept(server_fd,(struct sockaddr*)&address,(socklen_t*)&addrlen))<0){perror("accept");exit(EXIT_FAILURE);}/*accept() 是一个系统调用,用于从监听队列中取出第一个连接请求,并为该请求创建一个新的套接字。*///读取客户端发送的数据read(new_socket,buffer,1024);//读取数据到缓冲区cout<<"消息来自丽宝:"<<buffer<<endl;/*read() 是一个系统调用,用于从文件描述符(在这里是套接字)读取数据。new_socket是通过 accept() 函数创建的新套接字的文件描述符,用于与客户端进行通信*///发送数据回客户端send(new_socket,message,strlen(message),0);//发送消息cout<<"消息发送成功\n";//关闭套接字close(new_socket);//关闭客户端套接字close(server_fd);//关闭服务器套接字return 0;
}

2.2客户端(client.cpp)

客户端代码中有些在服务端代码中出现过,不清晰的看服务端代码解释就行

#include <iostream>  
#include <sys/socket.h> // 包含socket函数和数据结构
#include <arpa/inet.h> // 包含inet函数,用于IP地址转换
#include <unistd.h>  // 包含标准符号常数和类型
#include <string.h>  using namespace std;const int PORT = 1202; // 定义服务器的端口号int main() {int sock = 0; // 定义套接字文件描述符struct sockaddr_in serv_addr; // 定义服务器地址结构体const char *hello = "赟赟在干嘛!"; // 定义客户端发送的消息char buffer[1024] = {0}; // 定义接收数据的缓冲区/*sock 用于存储客户端套接字的文件描述符,它是网络通信中的一个重要概念,代表了网络通信的一端。*/// 创建套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {cout << "\n Socket creation error \n";return -1;}/*如果创建成功,sock 将包含一个非负值;如果创建失败,则为 -1。*/serv_addr.sin_family = AF_INET; // 服务器地址族serv_addr.sin_port = htons(PORT); // 服务器端口号// 将文本形式的IP地址转换为二进制形式if (inet_pton(AF_INET, "192.168.47.128", &serv_addr.sin_addr) <= 0) {cout << "\nInvalid address / Address not supported \n";return -1;}/*inet_pton() 用于将表示网络地址的字符串转换为网络字节序的二进制形式。*/// 连接到服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {cout << "\nConnection Failed \n";return -1;}/*connect() 用于客户端套接字与服务器套接字建立连接。*/// 发送数据send(sock, hello, strlen(hello), 0); // 发送消息cout << "消息发送成功:\n";// 接收服务器发送的数据read(sock, buffer, 1024); // 从服务器接收数据cout << "消息来自赟赟: " << buffer << std::endl;// 关闭套接字close(sock); // 关闭套接字return 0;
}

3.测试

在XShell中先执行

g++ -o server server.cpp
g++ -o client client.cpp

选择一个窗口先运行服务器

./server

然后另一个窗口运行客户端

./client

4.简易流程图

开始
服务器创建套接字
套接字创建成功?
设置套接字选项
打印错误并退出
选项设置成功?
绑定套接字到端口
绑定成功?
监听端口
监听成功?
等待客户端连接
接受客户端连接
接受成功?
读取客户端数据
读取成功?
发送数据回客户端
关闭套接字
结束
客户端创建套接字
套接字创建成功?
连接到服务器
连接成功?
发送数据到服务器
接收服务器响应
接收成功?
关闭套接字

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ALSC、IPLC、IEPL差异解说
  • ffmpeg视频转切片m3u8并加密videojs播放hls.js播放dplayer播放(弹幕效果)
  • FxFactory 8 for Mac 视觉特效插件包安装
  • CSS解析:层叠、优先级和继承
  • 【LeetCode】01.两数之和
  • 【内网渗透】内网信息收集的十三种基本方式
  • nvidia-cuda-tensorrt-cudnn下载网站
  • LLM 模型压缩之三: FoldGPT
  • 高级算法设计与分析 学习笔记3 哈希表
  • maven-helper插件解决jar包冲突实战
  • 使用udp进行通信
  • 宏碁扩展Swift系列,推出四款全新AI笔记本电脑
  • 番外 1 : 安装 docker 和 docker-compose
  • Oracl查询报错:ORA-29275: 部分多字节字符
  • vscode spring boot项目编辑yaml不自动提示补全如何解决
  • [笔记] php常见简单功能及函数
  • 「译」Node.js Streams 基础
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Android Volley源码解析
  • ES6 ...操作符
  • flutter的key在widget list的作用以及必要性
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • jquery ajax学习笔记
  • Python_网络编程
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • v-if和v-for连用出现的问题
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • Vue--数据传输
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 对JS继承的一点思考
  • 高性能JavaScript阅读简记(三)
  • 简单易用的leetcode开发测试工具(npm)
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 聊聊hikari连接池的leakDetectionThreshold
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • raise 与 raise ... from 的区别
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 容器镜像
  • ​HTTP与HTTPS:网络通信的安全卫士
  • !!Dom4j 学习笔记
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (Oracle)SQL优化技巧(一):分页查询
  • (STM32笔记)九、RCC时钟树与时钟 第二部分
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (备忘)Java Map 遍历
  • (二)PySpark3:SparkSQL编程
  • (佳作)两轮平衡小车(原理图、PCB、程序源码、BOM等)
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (一) storm的集群安装与配置
  • (已解决)什么是vue导航守卫
  • (转)负载均衡,回话保持,cookie
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)