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

C++小程序:同一路由器下两台计算机简单通信(1/2)——服务器端

       同一路由器下两台电脑如何进行通信呢?这里通过小程序实例的方式介绍SOCKET结构体以及相关函数的使用。计算机通信是在服务器端与客户端之间进行,这里先介绍服务器端程序。
       我这里编辑编译软件是VS2022,使用C++空项目进行编程。在介绍程序之前需要提醒大家,如果想把这个程序放到没有VS的计算机中使用,关于编译设置应如下进行:
       1.将Debug模式改为Release模式。
       2.右键方案名 -> 配置属性 -> c/c++ -> 代码生成 -> 运行库中选 多线程(/MT)。
       3.编译后在release目录下如找不到*.exe文件,可以在release模式下运行一下程序,然后再去找文件即可。
       4.如果使用的不是VS,也请注意一下编译问题,否则运行时会报错(缺少某些dll文件)。
       程序代码及相关解释如下:
       一、头文件部分:最基本的iostream应包含进来,并使用标准命名空间免得使用函数时还得注明作用域。WinSock2.h头文件及ws2_32.lib库文件是使用SOCKET结构及相关函数必须的。另外,还包含了关于多线程的thread头文件,处理通信过程的收和发如不使用多线程方式处理,收发之间相互影响,会造成不能连续发或连续收。

#include<iostream>
using namespace std;
#include <WinSock2.h>         
#pragma comment(lib,"ws2_32.lib")
#include<thread>
#pragma warning (disable: 4996) //解决C4996报错问题

       二、声明函数及变量
       在这里声明一个接收函数serverAccept和一个发送函数serverSend,之所以代码不多还要从主函数中拿出来另写成两个单独函数的原因,是因为这两个函数要装到单独的线程中去运行。
       需要声明全局变量pubServerSock、pubClientSock的理由也一样,主函数中声明的变量在其它线程中使用不了。

void serverRecv();//声明服务器端接收函数
void serverSend(); //声明服务器端发送函数
SOCKET pubServerSock; //声明服务器端全局SOCKET对象
SOCKET pubClientSock; //声明客户端全局SOCKET对象

        三、开始主函数代码编写,分成一下具体步骤:

int main(void)
{

       步骤1. 定义显示窗口。

	system("color 1A"); //定义窗口前景、背景颜色system("title Server Station"); //定义窗口system("mode con cols=60 lines=30");//定义窗口高宽

       步骤2. 打开网络库。打开网络库函数是WSAStartup函数,也可以理解成网络库初始化函数。在网络编程中,经常见到WSA字头,其含义:W-windows、S-socket、A-asynchronous(异步)。这个函数有两个参数,参1 系统在用的网络库版本号,右键头文件"WinSock2" 选择 "转到文档"可看到VS2022对应的网络库版本是2.2。这个版本号在计算机中是以WORD形式存储的,参数中不能直接写2.2,需要用MAKEWORD宏给转一下。参2 是一个WSADATA类型的结构体对象,这个对象需以指针形式传入,它的作用是保存一些网络库初始化信息,后边需要使用。
       打开网络库函数有返回值,成功返回0;不成功返回非0错误码。

	WORD thisVersion = MAKEWORD(2, 2); WSADATA SerSockData;int nRes = WSAStartup(thisVersion, &SerSockData);if(0 != nRes){cout << "网络库打开过程失败,程序即将结束!" << endl;system("pause");return 0; //结束程序运行}

步骤3. 校验版本(这一步骤可以略去)。如果校验版本未通过,在结束程序前,也要调用清理网络库函数。

	if (2 != HIBYTE(SerSockData.wVersion) || 2 != LOBYTE(SerSockData.wVersion)){cout<<"网络库版本出错误,程序即将结束!"<<endl;system("pause");WSACleanup();return 0; //结束程序运行}

       步骤4. 创建服务器端SOCKET对象,完成这一步骤的函数是socket函数。socket函数有3个参数,这3个参数是按照TCP/IP通信协议要求填写,内容不能更改。
       socket函数创建成功返回一个可用的SOCKET对象,这个对象在后面的操作中要用到,它以后就代表着服务器端计算机;如果创建失败返回INVALID_SOCKET,处理方式还是调用清理网络库函数。

	pubServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == pubServerSock){cout << "创建服务器端SOCKET对象失败,程序即将结束!" << endl;system("pause");WSACleanup(); return 0;//结束程序运行}

       步骤5. 利用bind函数将计算机IP地址、端口与前面创建的SOCKET对象绑定。这个函数有三个参数,参1 是前面创建成功的SOCKET对象;参2 是一个结构体,这个结构体中要填上本机服务器端IP地址、端口号等内容;参3 参2的字节大小。注意:函数中需要的是sockaddr*,我们填写的是sockaddr_in(这个易填),所以取址后要强转一下,因为这些内容绑定之后不能更改,所以强转时加上const。
       关于给sockaddr_in结构体对象赋值:
       a.成员1 sin_family选AF_INET是使用TCP/IP协议必须的;
       b.成员2 是端口号,可取值范围0-65535。低位的多被系统占用了所以要尽量往大了取,我这里选的是12345。选好后可以确认一下,方法:右键开始按钮->点击运行->输入cmd->DOS符号->输入netstat -ano|findstr "12345",如果没有什么显示就说明可用,如有显示说明系统已经使用了再换一个。htons是一个宏将int转换成sin_port所需格式。
       c.成员3 是服务器所在电脑的IP地址。如果是在一台电脑上模拟服务器端和客户端通信,IP地址选用"127.0.0.1"。inet_addr也是一个宏将字符串转换成规定格式。
        当在两台电脑运行时,填写服务器端电脑的实际IP地址。方法:右键开始按钮 -> 点击运行 ->输入cmd -> DOS符号 -> 输入ipconfig 选用IPv4后面的地址。
         bind函数运行成功,会将服务器的SOCKET对象与所在计算机IP地址绑定在一起,在网上这个对象就可以代表这台计算机了;如果运行失败,会返回SOCKET_ERROR,接下来先关闭服务器SOCKET对象再清理网络库,然后结束这个程序。

	sockaddr_in serverSockAdd; serverSockAdd.sin_family = AF_INET;serverSockAdd.sin_port = htons(12345);serverSockAdd.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //当两台电脑通信使用服务器电脑的IP地址if (SOCKET_ERROR == bind(pubServerSock, (const sockaddr*)&serverSockAdd, sizeof(serverSockAdd))){cout << "绑定服务器IP地址、端口失败,程序即将结束!" << endl;system("pause");closesocket(pubServerSock);WSACleanup(); return 0;//结束整个程序}

       步骤6. 开启监听函数listen()。监听函数有两个参数:参1 服务器端SOCKET对象,参2 挂起链接队列的最大长度。这个函数运行成功将把服务器端SOCKET对象置于侦听传入链接的状态;如果运行失败还是关闭SOCKET对象、清理网络库,然后结束程序。

	if (SOCKET_ERROR == listen(pubServerSock, SOMAXCONN)){cout << "服务器未进入侦听状态,程序即将结束!" << endl;system("pause");closesocket(pubServerSock);WSACleanup();return 0;//结束整个程序}

        步骤7. 使用Accept()函数创建客户端链接。在这一步骤服务器将与客户端建立联系。建立联系的方法是在服务器端建立一个客户端的SOCKET对象,通过两台计算机双方的SOCKET对象进行联系。这一步骤使用的函数是accept(),它的参数有三个:参1 服务器SOCKET对象(注意是服务器),参2 与bind函数中相同的结构,这个结构体是指向客户端的,所以不用我们填写,参3 参2的长度。
        accept()成功返回客户端的SOCKET对象(此时客户端计算机登录),并在屏幕上显示“链接成功”;失败返回INVALID_SOCKET,失败后的操作还是SOCKET对象、
清理网络库,然后结束程序。

	sockaddr_in clientSockAdd;int len = sizeof(clientSockAdd);pubClientSock = accept(pubServerSock,(sockaddr*)&clientSockAdd,&len);//struct sockaddr*前的const不能加了if (INVALID_SOCKET == pubClientSock){cout<<"客户端链接失败,程序即将结束!"<<endl;closesocket(pubServerSock);WSACleanup(); return 0;//结束整个程序}cout<<"客户端连接成功。。。"<<endl;

       步骤8. 与客户端之间接收、发送消息。全局变量及thread的作用在开始介绍头文件时,已经介绍,此处不再赘述。

	thread serverThread1(serverRecv);thread serverThread2(serverSend);serverThread1.join();serverThread2.join(); 

      步骤9. 程序结束。关闭所有SOCKET对象,清理网络库。

	closesocket(pubServerSock);closesocket(pubClientSock);WSACleanup(); system("pause");return 0; //程序结束
}

       四、子程序的实现
       1. serverRecv()是通过多线程对象调用的子程序,它的作用是接收客户端发过来的消息并进行显示。使用的函数是recv()。它有3个参数:参1 客户端SOCKET对象,参2 存储收到消息的字符数组 参3 缓冲内存大小 参4 接收模式,一般填0。recv运行正常返回收到的字节数;执行失败,返回SOCKET_ERROR,客户端下线或链接中断返回 0。

void serverRecv()
{while (true){char buf[1024] = { 0 };int res = recv(pubClientSock, buf, 1024 - 1, 0); if ( SOCKET_ERROR == res || 0==res){cout << "程序运行失败或链接中断" << endl;closesocket(pubServerSock);closesocket(pubClientSock);WSACleanup();system("pause");exit(0);}else{cout << buf << endl; //显示收到的内容}}
}

      2.serverSend()也是通过多线程对象调用的子程序,它的作用是向客户端发送消息。使用的函数是send(),它的参数个数及类型同及返回值都与recv()相似。

void serverSend()
{while (true){string buf;cin >> buf;int res = send(pubClientSock, buf.c_str(), strlen(buf.c_str()), 0);if (SOCKET_ERROR == res){cout << "程序运行失败或链接中断。。。" << endl;closesocket(pubServerSock);closesocket(pubClientSock);WSACleanup();system("pause");exit(0);}}
}

(接下一篇)

相关文章:

C++小程序:同一路由器下两台计算机简单通信(1/2)——服务器端

同一路由器下两台电脑如何进行通信呢&#xff1f;这里通过小程序实例的方式介绍SOCKET结构体以及相关函数的使用。计算机通信是在服务器端与客户端之间进行&#xff0c;这里先介绍服务器端程序。 我这里编辑编译软件是VS2022&#xff0c;使用C空项目进行编程。在介绍程序…...

EditReady for Mac激活版:专业视频转码工具

对于视频专业人员来说&#xff0c;一款高效的视频转码工具是不可或缺的。EditReady for Mac正是这样一款强大的工具&#xff0c;它拥有简洁直观的操作界面和强大的功能&#xff0c;让您的视频处理工作事半功倍。 EditReady for Mac支持多种视频格式的转码&#xff0c;并且支持常…...

Android app通过jcifs-ng实现Samba连接共享文件夹

Android端使用Samba连接共享文件夹&#xff0c;下载或上传文件的功能实现。如果你是用jcifs工具包&#xff0c;那么你要注意jcifs-ng 和 jcifs 支持的SMB版本区别。 JCIFS-NG的github地址 JCIFS官网地址 这里有关于jciffs、jcifs-codelibs、jcifs-ng、smbj的详细介绍 对比 支…...

linux开发笔记(buildroot打包镜像)

参考文章:https://www.cnblogs.com/arnoldlu/p/9553995.html mangopi_r3的buildroot在编译完成后会将所有镜像打包到一起。与之有关的buildroot配置项为 BR2_ROOTFS_POST_IMAGE_SCRIPT"board/allwinner/generic/scripts/genimage.sh" genimage.sh内容如下 #!/bin…...

预编码算法学习笔记

预编码算法是无线通信系统中的一项关键技术&#xff0c;它能够在发送端对信号进行处理&#xff0c;以提高系统的可靠性和频谱效率。以下是关于预编码算法的详细学习笔记。 1. 引言 在无线通信系统中&#xff0c;由于存在多径效应、信号衰减以及干扰等因素&#xff0c;接收到的…...

2024OD机试卷-最长子字符串的长度(一) (java\python\c++)

题目:最长子字符串的长度(一) 题目描述 给你一个字符串 s,首尾相连成一个环形,请你在环中找出 ‘o’ 字符出现了偶数次最长 子字符串 的长度。 输入描述 输入是一个小写字母组成的字符串 输出描述 输出是一个整数 用例1 输入 alolobo 输出 6 用例2 输入 looxdolx …...

docker 部署并运行一个微服务

要将微服务部署并运行在Docker容器中&#xff0c;你需要按照以下步骤操作&#xff1a; 编写Dockerfile&#xff1a;在项目根目录下创建一个名为Dockerfile的文件&#xff0c;并添加以下内容&#xff1a; # 使用一个基础的Docker镜像 FROM docker-image# 将项目文件复制到容器…...

Hive on Tez 作业优化参数

常用参数 参数名 参数说明 默认值 所在配置文件 关联问题 hive.tez.container.size Tez AppMaster向RM申请的container大小 -(单位:MB) hive-site.xml OOM tez.runtime.io.sort.mb 这个参数设定了 Tez 运行排序操作时可用的最大内存。排序操作的内存大小也会影响到排序的效率…...

flink mysql数据表同步API CDC

概述&#xff1a; CDC简介 Change Data Capture API CDC同步数据代码 package com.yclxiao.flinkcdcdemo.api;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.ververica.cdc.connectors.mysql.source.MySqlSource; import com.verv…...

AI大模型探索之路-训练篇21:Llama2微调实战-LoRA技术微调步骤详解

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…...

如何使用client-go构建pod web shell

代码示例及原理 原理是利用websocket协议实现对pod的exec登录&#xff0c;利用client-go构造与远程apiserver的长连接&#xff0c;将对pod容器的输入和pod容器的输出重定向到我们的io方法中&#xff0c;从而实现浏览器端的虚拟终端的效果消息体结构如下 type Connection stru…...

AI工具摸索-关于写作(1)

虽然人工智能工具非常多,但是如果想要成为生产力,能达标的工具仍然非常少,除了最常用的chatgpt,其他的工具真的能达标吗,这篇文章主要就是对比市面上的一些工具&#xff0c; 但我这个人非常执拗,我认为作为生产力工具的功能必然是可以真正帮助我们的,而不是说作为一个写作工具结…...

昂科烧录器支持O2Micro凹凸科技的电池组管理IC OZ7708

芯片烧录行业领导者-昂科技术近日发布最新的烧录软件更新及新增支持的芯片型号列表&#xff0c;其中O2Micro凹凸科技的电池组管理IC OZ7708已经被昂科的通用烧录平台AP8000所支持。 OZ7708是一款高度集成、低成本的电池组管理IC&#xff0c;适用于5~8s Li-Ion/Polymer电池组&a…...

Spring Cloud Gateway详解

文章目录 Gateway搭建路由&#xff08;route&#xff09;断言&#xff08;Predicate &#xff09;自定义断言 过滤器&#xff08;filter&#xff09;自定义全局过滤器 引言 在传统的单体项目中&#xff0c;前端和后端的交互相对简单&#xff0c;只需通过一个调用地址即可实现。…...

信息系统项目管理师0103:初步可行性研究(7项目立项管理—7.2项目可行性研究—7.2.2初步可行性研究)

点击查看专栏目录 文章目录 7.2.2初步可行性研究1.初步可行性研究定义2.辅助研究的目的和作用3.初步可行性研究的作用4.初步可行性研究的主要内容记忆要点总结7.2.2初步可行性研究 1.初步可行性研究定义 初步可行性研究一般是在对市场或者客户情况进行调查后,对项目进行的初步…...

Linux 系统中,nl命令用于计算文件中的行号

在 Linux 系统中&#xff0c;nl命令用于计算文件中的行号。它可以将输出的文件内容自动加上行号&#xff0c;并且可以通过不同的选项来设置行号的显示方式&#xff0c;包括行号的位数、是否自动补齐 0 等。其命令格式为&#xff1a;nl(选项)…(文件)…。以下是一些常见的选项&a…...

知从科技战略客户经理张志强受邀出席2024 AutoSec中国汽车网络安全与数据安全峰会

4月11-12日&#xff0c;AutoSec8周年年会暨中国汽车网络安全及数据安全合规峰会在上海成功举办。此次峰会吸引了来自全球各地的头部汽车网络安全企业、OEM厂商、安全专家和学者等齐聚盛会&#xff0c;零距离共话智能网联汽车产业的新发展、新趋势。 知从科技董事长成云霞亲自带…...

2024.5.12 Pandas 基础语法day02

#describe()作用是计算出各个列的描述行统计量如平均数&#xff0c;方差&#xff0c;最大值&#xff0c;最小值&#xff0c;四分位数&#xff0c;返回类型是 #pandas.core.frame.DataFrame import pandas as pd df pd.read_csv("Nowcoder.csv") print(df.describe()…...

Stable Diffusion是什么?

目录 一、Stable Diffusion是什么&#xff1f; 二、Stable Diffusion的基本原理 三、Stable Diffusion有哪些运用领域&#xff1f; 一、Stable Diffusion是什么&#xff1f; Stable Diffusion是一个先进的人工智能图像生成模型&#xff0c;它能够根据文本描述创造出高质量的图…...

Netty源码分析二NioEventLoop 剖析

剖析方向 NioEventLoop是一个重量级的类&#xff0c;其中涉及到的方法都有很复杂的继承关系&#xff0c;调用链&#xff0c;要想把源码全部过一遍工作量实在是太大了&#xff0c;于是小编就基于下面的这些常见的问题来对NioEventLoop的源码来进行剖析 1.Seletor何时创建 1.1Se…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...