WindowsAPI 查阅笔记:网络通信

news2024/9/21 16:18:55

客户端:

记得在编译的时候加上这个 -lwsock32 -lws2_32
不然会报错 undefined reference to `__imp_WSAStartup‘

注意:如果端口在此之前被占了,则不会发生预期的结果

服务端,得到连接后创建线程,执行处理函数。

client.cpp

//client.cpp
#include <cstdio>
#include <winsock2.h>
#include <iostream>
#include <cstring>
#include <windows.h>

//#pragma comment(lib, "ws2_32.lib") 

#define RECV_BUFFER_SIZE 8192

int main(int argc, char **argv)
{
	//变量定义
	SOCKADDR_IN clientService;	//地址
	SOCKET	ConnectSocket;		//Socket
	WSADATA	wsaData;			//库
//	LPVOID recvbuf;				//接收缓存
	char *recvbuf ;
//	char recvbuf[64];
	int bytesSent;
	int bytesRecv = 0;
	
	//默认的发送数据 
//	char sendbuf[32] = "get information"; 
	char sendbuf[32] = "download file";
	
	//初始化 Socket 库,保证 ws2_32.dll 已经加载
	int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(iResult != NO_ERROR){
		printf("Error at WSAStartup()\n");
	} 
	//创建 Socket
	ConnectSocket = socket(AF_INET,	//Ipv4
		SOCK_STREAM,	//顺序的、可靠的、基于链接的、双向数据流通信
		IPPROTO_TCP		//使用 TCP 协议 
	);
	if(ConnectSocket == INVALID_SOCKET)
	{
		printf("Error at socket(): %ld\n",
			WSAGetLastError());
		WSACleanup();
		return 3;
	}
	//设置服务端的通信协议、ip地址、端口
	clientService.sin_family = AF_INET;
	clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
	clientService.sin_port = htons(12321);
	//连接到服务端
	if(	connect(
		ConnectSocket,				//socket
		(SOCKADDR*) &clientService,	//地址
		sizeof(clientService)		//地址的大小
		) == SOCKET_ERROR 
	){
		printf("Failed to connect(%d)\n",WSAGetLastError());
		WSACleanup();
		return 2;
	}else{
		printf("连上了~!\n"); 
	}
	
	//准备发送数据
	// 如果输入的参数是 "-d" ,那么发生的数据事 "download file"
	// 否则发送的数据是 "get information"
	if(argc == 2 && (!lstrcmp(argv[1],"-d"))){
		lstrcpyn(sendbuf, "download file", 32);
	} 
	
	//向服务端发送数据
	bytesSent = send(ConnectSocket,	//socket
		sendbuf,					//发送的数据
		lstrlen(sendbuf)+1,			//数据长度
		0);							//无标志
	if(bytesSent == SOCKET_ERROR){
		printf("send error(%d)\n",
			WSAGetLastError());
		closesocket(ConnectSocket);
		return 1;
	} 
	printf("Bytes Sent: %ld\n",bytesSent);
	//准备接收数据
//	recvbuf = HeapAlloc(GetProcessHeap(), 0, RECV_BUFFER_SIZE);
	recvbuf = (char*)malloc(sizeof(char)*RECV_BUFFER_SIZE);
	//循环接收
	while(bytesRecv != SOCKET_ERROR)
	{
		
		bytesRecv = recv(ConnectSocket,	//socket
			recvbuf,					//接收数据缓存
			RECV_BUFFER_SIZE,			//缓存大小
			0);							//无标志
		if(bytesRecv == 0){
			printf("Connection Closed.\n");
			break;
		} 
		//TODO,处理接收到的数据,这里只简单地将收到的数据大小显示
		printf("Bytes Recv: %ld\n", bytesRecv); 
		printf("data:%s\n",recvbuf);
	} 
//	HeapFree(GetProcessHeap(), 0, recvbuf);
	free(recvbuf);
	WSACleanup();
	
	return 0;
} 

server.cpp

//  server.cpp 

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <cstring>
#include <cstdio>

//常量
#define DEFAULT_PORT "12321"	//端口
#define MAX_REQUEST 1024		//接收数据的缓存大小
#define BUF_SIZE	4096		//发送数据的缓存大小

/***************************
用于接收和发送数据的线程
	为每一个连接的客户端创建一个接收发送数据的线程,
	可以使用多个客户端同时连接到服务端 
**************************/ 

DWORD WINAPI CommunicationThread(LPVOID lpParameter)
{
	DWORD dwTid = GetCurrentThreadId();
	//获得参数 socket
	SOCKET socket = (SOCKET)lpParameter;
	//为接收数据分配空间
//	LPSTR szRequest = HeapAlloc(GetProcessHeap(), 0, MAX_REQUEST); 
	char *szRequest = (char *)malloc(sizeof(char)*MAX_REQUEST);
	int iResult;
	//用于保存send 的返回值,既实际发送的数据的大小 
	int bytesSent;	
	
	//接收数据
	iResult = recv(socket,	//socket
		szRequest,			//接收缓存
		MAX_REQUEST,		//缓存大小
		0);					//标志
	if(iResult == 0){	//接收数据失败,连接已关闭
		printf("COnnection closing...\n");
//		HeapFree(GetProcessHeap(), 0, szRequest);
		free(szRequest);
		closesocket(socket);
		return 1;
	}else if(iResult == SOCKET_ERROR){//接收数据失败,Socket 错误
		printf("recv failed: %d\n",WSAGetLastError());
//		HeapFree(GetProcessHeap(), 0, szRequest);
		free(szRequest);
		closesocket(socket);
		return 1;
	}else if(iResult > 0){	//接收数据成功 
		//显示接收到的数据
		printf("\tCommunicationThread(%d)\tBytes received: %d\n",dwTid, iResult);
		printf("\tCommunicationThread(%d)\trequest string is (%s)\n",dwTid, szRequest);
		
		//如果接收到的数据是 "download file"
		if(lstrcmpi(szRequest, "download file") == 0){
			//读取文件 download.txt 将发送
			HANDLE hFile;
//			LPVOID lpReadBuf;	//发生缓存
			char *lpReadBuf;
			
			DWORD dwBytesRead;
			DWORD dwFileSize;
			DWORD dwSendFile = 0;
			hFile = CreateFile("download.txt",
				GENERIC_READ,
				FILE_SHARE_READ,
				NULL,
				OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL,
				NULL);
				
			if(hFile == INVALID_HANDLE_VALUE){
				printf("\tCommunicationThread\tCould not open file (error %d)\n",
					GetLastError());
				send(socket, "error", 6, 0);
				closesocket(socket);
				return 1;
			} 
			//分配发送数据的缓存
//			lpReadBuf = HeapAlloc(GetProcessHeap(), 0, BUF_SIZE);
			lpReadBuf = (char*) malloc(sizeof(char) * BUF_SIZE);
			//获取文件的大小
			dwFileSize = GetFileSize(hFile, NULL);
			//循环发送
			while(1){
				//读文件到缓存
				if(!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL)){
					printf("\tCommunicationThread\tCould not read from file (error %d)\n",
						GetLastError());
					closesocket(socket);
					CloseHandle(hFile);
					return 1;
				} 

				//发送读取的文件数据
				bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);
				if(bytesSent == SOCKET_ERROR){
					printf("\tCommunicationThread\tsend error %d\n",WSAGetLastError());
					closesocket(socket);
					CloseHandle(hFile);
					return 1; 
				} 
				//显示发送数据的大小
				printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
				//累加,已经发送的大小
				dwSendFile += dwBytesRead;
				//如果所以文件数据都已经发送
				if(dwSendFile == dwFileSize){
					printf("\tCommunicationThread\tFile download ok\n");
					break;
				} 
			}
			//释放内存、关闭连接、关闭文件
	//		HeapFree(GetProcessHeap(), 0, lpReadBuf);
			free(lpReadBuf);
			CloseHandle(hFile);
			closesocket(socket); 
		}
		//如果接收到的数据 是 "get information"
		
		else if(lstrcmpi(szRequest, "get information") == 0){
			//发送数据 
			bytesSent = send(socket,	//socket
				"this is information",	//数据
				lstrlen("this is information")+1,//数据长度
				0);	//标志
			//判断是否成功
			if(bytesSent == SOCKET_ERROR){
				printf("\tCommunicationThread\tsend error %d\n",
					WSAGetLastError());
				closesocket(socket);
				return 1;
			} 
			printf("\tCommunicationThread(%d)\tsend %d bytes\n",dwTid, bytesSent);
		} else{
			//收到未知数据
			printf("unreferenced request\n"); 
		}
	}
		//释放接收数据缓存 ,关闭Socket
	//	HeapFree(GetProcessHeap(), 0, szRequest);
	free(szRequest);

	closesocket(socket);
	return 0;
}

/***************************
socket 服务端主程序 
************************/

int __cdecl main(void)
{
	WSADATA wsaData;
	//监听 Socket 
	SOCKET ListenSocket = INVALID_SOCKET;	 
	//连接 Socket
	SOCKET ClientSocket = INVALID_SOCKET;
	
	struct addrinfo *result = NULL, hints;
	int iResult;		//保存返回的结果
	
	
	//初始化 WinSock,保证 Ws2_32.dll 已经加载
	iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(iResult != 0){
		printf("WSAStartup failed: %d\n",iResult);
		return 1;
	}
	
	//地址
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;
	
	//获取主机地址,保证网络协议可用等
	iResult = getaddrinfo(NULL,	//本机
		DEFAULT_PORT,		//端口
		&hints,				//使用的网络协议、连接类型等
		&result);			//结果
	if(iResult != 0){
		printf("getaddrinfo failed: %d\n",iResult);
		WSACleanup();
		return 1;
	} 
	//创建 Socket,用于监听
	ListenSocket = socket(
		result->ai_family,	//网络协议,AF_INET,Ipv4
		result->ai_socktype,	//类型,SOCK_STREAM
		result->ai_protocol	//通讯协议,TCP 
	);
	if(ListenSocket == INVALID_SOCKET){
		printf("socket failed: %ld\n",
			WSAGetLastError());
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	} 
	
	//绑定到端口
	iResult = bind(ListenSocket,
		result->ai_addr,
		(int)result->ai_addrlen)
	;
	if(iResult == SOCKET_ERROR){
		printf("bind failed: %d\n",WSAGetLastError());
		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	} 
	printf("bind\n");
	
	freeaddrinfo(result);	//reuslt 不再使用
	
	//开始监听
	iResult = listen(ListenSocket, SOMAXCONN);
	printf("start listen......\n");
	if(iResult == SOCKET_ERROR)
	{
		printf("listen failed: %d\n",WSAGetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	} 
	while(1){
		//接收客户端连接,accept函数会等待,直到连接建立
		printf("ready to accept\n");
		ClientSocket = accept(ListenSocket, NULL, NULL);
		//accept 函数返回,说明已经有客户端连接
		//返回连接 Socket
		printf("accept a connetion\n");
		if(ClientSocket == INVALID_SOCKET){
			printf("accept failed: %d\n",WSAGetLastError());
			closesocket(ListenSocket);
			break;//等待连接错误,退出循环 
		} 
		//为每一个连接创建一个数据发送的接收线程
		//使服务端又可以立即接收到其他客户端的连接
		if(!CreateThread(
			NULL,
			0,
			CommunicationThread,	//线程函数
			(LPVOID)ClientSocket,	//将Socket 作为传入参数
			0,
			NULL))
		{
			printf("Create Thread error (%d)",
				GetLastError());
			break; 
		} 
	}
	//循环退出,释放DLL
	WSACleanup();  
	return 0;
}

download.txt

Hello,This is download.txt
你好,这里是 download.txt 文件
hello, 这里是 download.txt file. 

运行结果

先运行 server 再运行 client。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

你真的了解电子标签的潜力吗?3秒快刷颠覆你的想象

随着ESL电子标签在零售领域的大范围应用&#xff0c;其方便快捷更改显示内容的功能也逐渐拓展到仓储显示领域。但是仓储作业过程中货品出入库频繁&#xff0c;常规电子标签在实际使用过程中存在刷新速度偏长&#xff0c;无法充分满足仓储出入库数据更新的需求。因此&#xff0c…

阿里云智能大数据演进

本文根据7月24日飞天发布时刻产品发布会、7月5日DataFunCon2024北京站&#xff1a;大数据大模型.双核时代实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a;徐晟 阿里云研究员/计算平台产品负责人 主要内容&#xff1a; Overview - 阿里云大数据 AI 产品…

秋招突击——面经整理——有塔游戏提前批

文章目录 引言正文一面说一下堆排序 二面有了解过游戏后端应该是干什么的吗&#xff1f;博客是从什么时候开始写的&#xff1f;平常在哪里做题&#xff1f;做了多少题&#xff1f;给你二维矩阵&#xff0c;零代表可以走&#xff0c;一代表不可以走&#xff0c;从起点到终点&…

Java:文件IO

JavaEE16 一、文件系统操作 在java标准库中&#xff0c;实现了File类&#xff0c;其中提供了文件操作的方法&#xff01; 1、构造方法&#xff1a; 方法名说明 File(File parent , String child) 根据父目录孩子文件路径&#xff0c;创建一个新的File 实例File( String path…

dockers 阿里云镜像失效后如何配置,可视化操作

Windows 环境 Client:Version: 24.0.6Context: defaultDebug Mode: false方法一 docker-desktop 配置方式 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,…

【echarts】甘特图

const milestones [{ progress: 100, milestoneName: 阶段一, startDate: 2020-12-23, endDate: 2021-01-30 },{ progress: 100, milestoneName: 阶段二, startDate: 2021-01-15, endDate: 2021-03-15 },{ progress: 100, milestoneName: 阶段三, startDate: 2021-03-10, endD…

ubuntu 24.04执行apt-get update报错处理

文章目录 一、apt-get update报错内容二、解决启动失败的服务推荐阅读 今天在做Ubuntu 24.04更新时&#xff0c;突然跳出两个报错&#xff0c;这在之前还从未遇到过&#xff0c;处理过程记录和分享一下&#xff1a; 一、apt-get update报错内容 报错截图参考如下&#xff1a; …

现货黄金美盘开盘时间是什么呢

现货黄金的开盘时间会因为地区和平台而有所差异&#xff0c;一般来说&#xff0c;香港的平台在北京时间周一早间7点左右会开盘&#xff0c;并一直持续周六凌晨才收盘&#xff0c;周六和周日是市场的休市时间&#xff0c;期间交易平台一般会关闭&#xff0c;无法进行交易&#x…

一文读懂什么是进销存!进销存有何价值作用?

企业在运营过程中&#xff0c;常常会遇到诸如库存不准确、采购计划混乱、销售数据跟踪困难等问题&#xff0c;这些问题不仅影响了企业的日常运营&#xff0c;还可能导致客户满意度下降、利润受损。而一个合适的进销存系统&#xff0c;就像是一把钥匙&#xff0c;可以帮助企业打…

MySQL基础练习题34-游戏玩法分析4

目录 题目 准备数据 分析数据 总结 题目 报告在首次登录的第二天再次登录的玩家的 比率&#xff0c;四舍五入到小数点后两位。换句话说&#xff0c;你需要计算从首次登录日期开始至少连续两天登录的玩家的数量&#xff0c;然后除以玩家总数。 准备数据 ## 创建库 create…

为什么要学医疗器械维修?

在当今高速发展的医疗领域&#xff0c;医疗器械维修已成为一个极具吸引力和潜力的职业选择。那么&#xff0c;为什么要学习医疗器械维修呢&#xff1f; 一、稳定且持续增长的需求 随着医疗技术的不断进步&#xff0c;医疗器械的种类和数量日益增多。从常见的 X 光机、CT 扫描仪…

新专利:温室土壤温湿度预测模型构建方法和程序产品

&#xff08; 于景鑫 国家农业信息化工程技术研究中心&#xff09;在现代设施农业生产中&#xff0c;温室微环境的精准调控是提高作物产量和品质的关键。然而&#xff0c;由于温室内外环境因素的复杂多变&#xff0c;尤其是土壤温湿度的非线性、非平稳特性&#xff0c;传统的预…

【vue3|第23期】Vite + Vue3: 深入理解public和assets文件夹的作用与使用

日期&#xff1a;2024年8月14日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

如果让你消息队列,该如何设计?说一下你的思路

在当今的分布式系统中&#xff0c;消息队列是一个不可或缺的组件&#xff0c;它在系统解耦、流量削峰、异步处理等方面发挥着重要作用。 如果我要设计一个消息队列&#xff0c;我会从以下几个关键点出发呢&#xff1f; 让我们来探讨一下如何设计一个消息队列的架构。 实现内存…

【MySQL】数据库初识

文章目录 前言一、MySQL的基本结构二、MySQL的组成三、数据库的简单使用数据库操作数据类型认知数值类型字符串类型日期类型 数据库表操作 总结 前言 数据库是一类软件&#xff0c;有MySQL、Oracle、SQL Server、Redis等作为代表&#xff0c;通过数据库能够对数据进行管理和组…

六大热门及两个趋冷的网络安全趋势

AI不仅在改变威胁环境,还在改变安全团队保护其组织的方式,然而,AI并不是网络安全专业人士应该关注的唯一趋势。 在网络安全领域,与其他领域一样,AI和GenAI都是人们关注的焦点,恶意行为者正在利用AI和GenAI创造更具隐蔽性的恶意软件、更具说服力的钓鱼邮件以及更逼真的深…

DevExpress开发WPF应用实现对话框总结:编织界面的艺术之旅

在软件开发的浩瀚星空中&#xff0c;WPF&#xff08;Windows Presentation Foundation&#xff09;以其卓越的界面表现力和丰富的控件库&#xff0c;成为了众多开发者心中的璀璨明珠。而DevExpress&#xff0c;作为WPF领域的佼佼者&#xff0c;更是以其强大的组件库和易于集成的…

大模型时代来临:程序员如何自处,产品经理如何迎接新挑战

一名失业中的程序员&#xff0c;因为一次大胆的求职之举登上了微博热搜。 向瑶函花费999元&#xff0c;在广州地铁珠江新城站购买了一个广告位5天的使用权&#xff0c;用来投放自己的简历二维码&#xff0c;扫码就可以了解这名程序员“飘零的前半生”。 向瑶函是在2023年5月“…

灵巧守门员——代理模式(Java实现)

代理模式不仅在控制对象访问上展现了其独特的优势&#xff0c;还在功能扩展和系统安全性上起到了重要作用。上期我们介绍了代理模式在Python中的实现&#xff0c;今天&#xff0c;我们将继续探讨代理模式&#xff0c;并展示如何在Java中实现它。 什么是代理模式&#xff1f; …

How do you implement OpenAI GPT-3 Api Client in PHP?

题意&#xff1a;如何在 PHP 中实现 OpenAI GPT-3 API 客户端&#xff1f; 问题背景&#xff1a; I need help understanding the vague instructions on https://packagist.org/packages/orhanerday/open-ai 我需要帮助来理解这些模糊的说明... I downloaded the package fr…