C++11实现计算机网络中的TCP/IP连接(Windows端)

news2024/9/25 8:34:50

目录

  • 引言
  • 1、TCP
  • 2、IP
    • 2.1 IP路由器
  • 3、TCP/IP
  • 4、TCP/IP协议C++11实现
  • 参考文献

引言

TCP/IP传输控制协议/网际协议(Transmission Control Protocol / Internet Protocol)[1]
在TCP/IP协议簇中主要包含以下内容:

  • TCP (传输控制协议) - 应用程序之间通信
  • UDP (用户数据报协议) - 应用程序之间的简单通信
  • IP (网际协议) - 计算机之间的通信
  • ICMP (因特网消息控制协议) - 针对错误和状态
  • DHCP (动态主机配置协议) - 针对动态寻址

TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。

1、TCP

TCP 用于应用程序之间的通信。
TCP使用固定的连接,会建立一个全双工的通信。
会占用两个计算机之间通信线路,直到被一方或者双方关闭。

2、IP

IP是计算机之间的通信。
IP是无连接的通信协议,不会占用两个正在通信计算机之间的通信线路。
因此IP降低对网络线路的需求,每条线可以同时满足不同计算机之间的通信需要。

2.1 IP路由器

IP包从一台计算机被发送,它会到达一个IP路由器。

IP路由器会路由这个IP包到它的目的地,直接地或者通过其它路由器。
相同通信,一个包经过的路径可能和其它包不同,而路由器会根据通信量网络中错误其它参数进行正确寻址。

3、TCP/IP

TCP/IP是不同通信协议的大集合。[1]
TCP(应用程序与应用程序之间建立的全双工通信协议),IP(计算机与计算机之间建立的通信协议)。

  • TCP负责将数据分割装入IP包,然后在到达的时候重新组合它们。
  • IP则在中间负责将包发送至接受者。

如下图表示:
在这里插入图片描述

IP地址:计算机的“门牌”号,有了IP地址才可以接入因特网。IP包就像快递,得知道IP地址才能发送到对应的计算机。
TCP/IP使用4组数字为计算机编址,每个计算机有唯一的4组数字地址。每组数字必须在0~255之间,并用点号分割开,这里使用的是ipv4协议

为什么TCP/IP每个地址是使用0~255之间数字?
因为规定TCP/IP协议使用32个bit编址,在计算机中 8bit=1byte=1B,所以使用四个字节来编址。
然后8bit = 8 位,因此每组地址的范围就是
0000 0000 ~ 1111 1111,范围是0 ~ 2^8 - 1,也就是0 ~ 255。

TCP/IP简化了OSI的七层模型为四层模型。

  • 优化结构。
  • 每层独立但又因为上层协议使用下层协议服务,之间又存在联系。
    在这里插入图片描述

4、TCP/IP协议C++11实现

Linux下网络编程主要分为四个步骤[2]

  • 1、调用 socket 函数创建套接字。
  • 2 、调用 bind 函数分配IP地址和端口号。
  • 3、调用 listen 函数转换为可接受请求状态。
  • 4、调用 accept 函数受理套接字请求。

套接字是通信中两个网路应用程序进行通信时,各自连接中的端点[3]。是通信的基石。
套接字socket表示方法是(ip地址:端口号)或(ip地址,端口号)。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。例如:如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)[4]

上面引用[2]里描述的整个流程是这样的,比喻为打电话。
首先需要安装电话机,因此使用套接字socket,然后分配端口号,也就是电话号码,使用bind函数给创建号的套接字分配ip地址和端口信息。有了电话和电话号码之后,需要架设电话线,使用listen函数让这台电话可用,这时其他人可以打电话到这台电话机,电话机响的时候需要接听,最后使用accept函数来保持监听。

那么我们就简单来实现一个hello world在windows下的传输。

首先我们需要建立一个服务端项目,它能够在收到信息时进行回传hello world。

  • 服务端的职能:建立socket,声明自身的端口号和地址并绑定到socket,使用listen打开监听,然后不断用accept去查看是否有连接,如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket,如果不再需要等待任何客户端连接,那么用closeSocket关闭掉自身的socket
  • 客户端职能:建立socket套接字,通过ip地址和端口号确定目标服务器。使用connect连接服务器,使用send函数发送消息,等待服务器处理,通信完成后调用closeSocket关闭socket。

参考这位朋友的博客[5]实现了基本的服务端架设,服务端代码和注释转载于(初学者的福音)windows下实现socket通信(TCP/IP)代码详解——服务端篇。

/*****************************************************************************************************************************
*	1、加载套接字库,创建套接字(WSAStartup()/socket());
*	2、绑定套接字到一个IP地址和一个端口上(bind());
*	3、将套接字设置为监听模式等待连接请求;
*	4、请求到来之后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
*	5、用返回的套接字和客户端进行通信(send()/recv());
*	6、返回,等待另一个连接请求
*	7、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());
*****************************************************************************************************************************/
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")

int main()
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;//WSADATA结构体变量的地址值

	//int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
	//成功时会返回0,失败时返回非零的错误代码值
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		cout << "WSAStartup() error!" << endl;
		return 0;
	}

	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		cout << "socket error !" << endl;
		return 0;
	}

	//绑定IP和端口
	sockaddr_in sin;//ipv4的指定方法是使用struct sockaddr_in类型的变量
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);//设置端口。htons将主机的unsigned short int转换为网络字节顺序
	sin.sin_addr.S_un.S_addr = INADDR_ANY;//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址
	//bind函数把一个地址族中的特定地址赋给scket。
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !");
	}

	//开始监听
	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		cout << "listen error !" << endl;
		return -1;
	}

	//循环接收数据
	SOCKET sclient;
	sockaddr_in remoteAddr;//sockaddr_in常用于socket定义和赋值,sockaddr用于函数参数
	int nAddrlen = sizeof(remoteAddr);
	char revData[255];
	while (true)
	{
		cout << "等待连接。。。" << endl;
		sclient = accept(slisten, (sockaddr*)&remoteAddr, &nAddrlen);
		if (sclient == INVALID_SOCKET)
		{
			cout << "accept error !" << endl;
			continue;
		}
		cout << "接收到一个连接:" << inet_ntoa(remoteAddr.sin_addr) << endl;
		//接收数据
		int ret = recv(sclient, revData, 255, 0);
		if (ret > 0)
		{
			revData[ret] = 0x00;
			cout << revData << endl;
		}
		//发送数据
		const char* sendData = "你好,TCP客户端!\n";
		send(sclient, sendData, strlen(sendData), 0);
		closesocket(sclient);
	}
	closesocket(slisten);
	WSACleanup();
	system("pause");
	//return 0;
}

客户端实现,客户端代码来源于windows环境下用c++实现socket编程:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<WINSOCK2.H>
#include<STDIO.H>
#include<iostream>
#include<cstring>
using namespace std;
#pragma comment(lib, "ws2_32.lib")


int main()
{
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA data;
	if (WSAStartup(sockVersion, &data) != 0)
	{
		return 0;
	}
	while (true) {
		SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (sclient == INVALID_SOCKET)
		{
			printf("invalid socket!");
			return 0;
		}

		sockaddr_in serAddr;
		serAddr.sin_family = AF_INET;
		serAddr.sin_port = htons(8888);
		serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
		if (connect(sclient, (sockaddr*)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
		{  //连接失败 
			printf("connect error !");
			closesocket(sclient);
			return 0;
		}

		string data;
		cin >> data;
		const char* sendData;
		sendData = data.c_str();   //string转const char* 
		//char * sendData = "你好,TCP服务端,我是客户端\n";
		send(sclient, sendData, strlen(sendData), 0);
		//send()用来将数据由指定的socket传给对方主机
		//int send(int s, const void * msg, int len, unsigned int flags)
		//s为已建立好连接的socket,msg指向数据内容,len则为数据长度,参数flags一般设0
		//成功则返回实际传送出去的字符数,失败返回-1,错误原因存于error 

		char recData[255];
		int ret = recv(sclient, recData, 255, 0);
		if (ret > 0) {
			recData[ret] = 0x00;
			printf(recData);
		}
		closesocket(sclient);
	}


	WSACleanup();
	return 0;

}

先运行服务端,再运行客户端,然后输入内容,便可以通过TCP/IP传输。

最终结果:
在这里插入图片描述

后续解析待更新。。。

参考文献

[4] 潘伟编著,计算机网络 理论与实验,厦门大学出版社,2013.12,第145页

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

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

相关文章

Bing引擎引入ChatGPT申请候补名单方式

Bing引入ChatGPT申请候补名单方式ChatGPT一、ChatGPT简介二、OpenAI和Google的"军备军赛"三、ChatGPT版本⭐Bing引擎引入ChatGPT申请候补名单方式1.下载chrome拓展程序2.配置拓展程序3.Bing 申请候补名单3.1旧版本Bing3.2新版本Bing4.等待获取结尾ChatGPT 一、ChatG…

Linux ALSA 之十:ALSA ASOC Machine Driver

ALSA ASOC Machine Driver一、Machine 简介二、ASoC Machine Driver2.1 Machine Driver 的 Platform Driver & Platform Device 驱动模型2.2 在 Probe() 中注册声卡三、snd_soc_register_card 函数3.1 bind DAIs3.2 New a sound card3.3 Create card new widgets3.4 Probe …

JointBERT代码复现详解【上】

BERT for Joint Intent Classification and Slot Filling代码复现【上】 源码链接&#xff1a;JointBERT源码复现&#xff08;含注释&#xff09; 一、准备工作 源码架构 data&#xff1a;存放两个基准数据集&#xff1b;model&#xff1a;JointBert模型的实现&#xff1b…

修改本地host文件加入可用ip使谷歌浏览器翻译插件重新生效

修改本地host文件加入可用ip使谷歌浏览器翻译插件重新生效 第一步&#xff1a;找到host文件&#xff1a; 可以使用这个工具进行对Hosts文件进行一个查找 鼠标放到对应路径上面 点击鼠标右键&#xff0c;选择打开路径就到对应 路径了 也可以复制到这个路径下面去找hosts文件 …

【Node.js实战】一文带你开发博客项目之Koa2重构(实现session、开发路由、联调、日志)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

Redis集群搭建(主从、哨兵、分片)

1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录&#xff1a; 例如&#xff0c;我放到了/tmp目录&#xff1a; 解压缩&#xff1a; tar -xzf redis-6.2.4.tar.gz解压后&#xff1…

C# Lambda表达式含义及各种写法

Lambda表达式在各个语言中的表达方式都不太相同&#xff0c;本文重点介绍C#的Lambda表达式。 首先&#xff0c;Lambda表达式就是一个匿名的方法/函数。 以下面的一个完整版作为例子&#xff0c;前面是参数&#xff0c;后面是返回值&#xff1a; 由于 Lambda表达式和委托常常一起…

AI推理计算框架中的内存优化

背景 内存管理是AI计算中非常重要的一部分。我们希望模型计算时占用内存尽可能小&#xff0c;这样我们训练或推理时就可以用更大的batch size使其尽快收敛&#xff0c;或者提高吞吐率。又或者让我们可以使用参数更多、或更复杂的模型从而达到更好的准确率。由于现代深度学习模…

【MySQL数据库】主从复制原理和应用

主从复制和读写分离1. 主从复制的原理2. 主从复制的环境配置2.1 准备好数据库服务器2.2 配置master2.3 配置slave2.4 测试3. 主从复制的应用——读写分离3.1 读写分离的背景3.2 Sharding-JDBC介绍3.3 Sharding-JDBC使用步骤1. 主从复制的原理 MySQL主从复制是一个异步的过程&a…

微服务 RocketMQ-延时消息 消息过滤 管控台搜索问题

~~微服务 RocketMQ-延时消息 消息过滤 管控台搜索问题~~ RocketMQ-延时消息实现延时消息RocketMQ-消息过滤Tag标签过滤SQL标签过滤管控台搜索问题RocketMQ-延时消息 给消息设置延时时间&#xff0c;到一定时间&#xff0c;消费者才能消费的到&#xff0c;中间件内部通过每秒钟扫…

TCP的运输连接管理

TCP的运输连接管理 文章目录TCP的运输连接管理TCP报文格式简介首部各个字段的含义控制位(flags)TCP的连接建立抓包验证一些细节及解答TCP连接释放抓包验证一些细节及解答参考TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放时每一次面向连接的通信…

第一部分:简单句——第一章:简单句的核心——二、简单句的核心变化(主语/宾语/表语的变化)

二、简单句的核心变化 简单句的核心变化其实就是 一主一谓&#xff08;n. v.&#xff09; 表达一件事情&#xff0c;谓语动词是其中最重要的部分&#xff0c;谓语动词的变化主要有四种&#xff1a;三态加一否&#xff08;时态、语态、情态、否定&#xff09;&#xff0c;其中…

MSI_MSI-X中断之源码分析

MSI_MSI-X中断之源码分析 文章目录MSI_MSI-X中断之源码分析一、 怎么发出MSI/MSI-X中断1.1 在RK3399上体验1.1.1 安装工具1.1.2 查看设备MSI-X信息1.1.3 验证MSI-X信息二、 怎么使用MSI/MSI-X三、 MSI/MSI-X中断源码分析3.1 IRQ Domain创建流程3.1.1 GIC3.1.2 ITS3.1.3 PCI MSI…

Linux C/C++ timeout命令实现(运行具有时间限制)

Linux附带了大量命令&#xff0c;每个命令都是唯一的&#xff0c;并在特定情况下使用。Linux timeout命令的一个属性是时间限制。可以为任何命令设置时间限制。如果时间到期&#xff0c;命令将停止执行。 如何使用timeout命令 我们将解释如何使用Linux timeout命令 timeout […

七、Git远程仓库操作——团队成员内协作

1. github远程协作的两种方式 前面我写的笔记&#xff0c;都是自己一个人在玩&#xff0c;无论是本地操作还是推送到远程都是自己推送到自己的仓库。 如果是别人拥有这个仓库&#xff0c;而我想对这个仓库的内容更改后&#xff0c;然后想推送更新到这个仓库&#xff0c;我们要…

【随笔】我迟到的2022年度总结:突破零粉丝,1个月涨粉1000+,2023年目标3万+

前言 我是21年12月注册的csdn&#xff0c; 作为用户平时看看文章&#xff0c;从未参与过写文章这件事。 但这一年的时间我见证了很多新号的崛起&#xff0c;有的号我平时关注比较多&#xff0c;看着他们从零粉丝突破了三万甚至五万的粉丝量。 在csdn上遇到了我的贵人&#x…

位运算 | 1356. 根据数字二进制下 1 的数目排序

LeetCode 1356. 根据数字二进制下 1 的数目排序 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。如果存在多个数字二进制中 1 的数目相同&#xff0c;则必须将它们按照数值大小升序排列。 文章讲解https://www.programmercarl.com/1356.%…

【微电网】基于风光储能和需求响应的微电网日前经济调度(Python代码实现)

目录 1 概述 2 知识点及数学模型 3 算例实现 3.1算例介绍 3.2风光参与的模型求解 3.3 风光和储能参与的模型求解 3.5 风光储能和需求响应都参与模型求解 3.6 结果分析对比 4 Python代码及算例数据 1 概述 近年来&#xff0c;微电网、清洁能源等已成为全球关注的热点…

Linux Vim编辑器基础讲解

目录 vim三个模式 命令模式 输入模式&#xff08;insert 插入模式、编辑模式&#xff09; 末行模式 编辑简单文档 什么是vim Vim是文本编辑器&#xff0c;是Linux上最常用的文本编辑器 Vim可以建立、编辑、显示文件 绝大多数Linux都会携带vim或者vi vim编辑器和vi编辑器的…

windbg-应用层实时调试

调试符号windbg使用一个或多个目录来存放符号条件&#xff0c;并使用环境变量_NT_SYMBOL_PATH来指向这些环境变量的位置&#xff0c;对操作系统内部模块的符号文件&#xff0c;一般用http://msdl.microsoft.com/download/symbols配置如下&#xff1a;SRV*C:\Symbols*http://msd…