win32 基础数据发送与接收

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32 基础数据发送与接收相关的知识,希望对你有一定的参考价值。

前言

Win32中发送基础网络数据相比起其他语言如java可能比较复杂。

大致流程:

  1. 导入Ws2_32.lib
  2. 根据一定规范初始化Ws2_32.lib
  3. 创建套接字对象,用于指定协议类型
  4. 绑定套接字所指定的端口
  5. 调用收发函数
  6. 资源回收
  • (1)导入Ws2_32.lib

有两种方式指示导入动态库

  1. 编译宏指示连接器
#pragma comment(lib,"Ws2_32.lib")
  1. VS中配置

  • (2)初始化Ws2_32.lib

WSAStartup 文档

这里我们直接抄官方文档代码即可


int main()
{

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\\n", err);
		return 1;
	}

	/* Confirm that the WinSock DLL supports 2.2.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.2 in addition to 2.2, it will still return */
	/* 2.2 in wVersion since that is the version we      */
	/* requested.                                        */

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\\n");
	
	WSACleanup();
}

  • (3) 创建套接字对象,用于指定协议类型

	//(2)创建套接字对象,用于指定协议类型
	//https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
	SOCKET sockServer = socket(
		AF_INET,//指定协议是IPV4 还是IPV6.AF_INET是IPV4,AF_INET6是IPV6
		SOCK_DGRAM,//指定是TCP(SOCK_STREAM)或者UDP(SOCK_DGRAM)
		IPPROTO_UDP//指定具体的协议类型,如ICMP,IPPROTO_TCP或IPPROTO_UDP 
	);

	if (sockServer == INVALID_SOCKET)
	{
		printf("创建socket失败 \\r\\n");
		return 0;
	}
  • (4) 绑定套接字所指定的端口
//(3)绑定套接字所指定的端口
	sockaddr_in si;
	si.sin_family = AF_INET;
	//htons函数用于转化大小端,网络传输字节流统一采用大端
	//但在x86使用小端编码,所以利用htons屏蔽大小端
	si.sin_port = htons(0x5566);
	//inet_addr同上
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//绑定端口
	int nRet = bind(
		sockServer,//指定的协议
		(sockaddr *)&si,//指定的端口信息
		sizeof(si)
	);
	if (nRet == SOCKET_ERROR)
	{
		printf("绑定端口失败\\r\\n");
		WSACleanup();
		return 0;
	}

(5). 调用收发函数 和 (6) 资源回收

/接收数据
	sockaddr_in siRecf;

	char aryBuf[MAXBYTE] = { 0 };
	int nNameLen = sizeof(siRecf);
	while (true)
	{
		//接收信息
		nRet = recvfrom(
		sockServer, //协议
		aryBuf,//接收的字节数组
		 sizeof(aryBuf),//接收大小
		  0,//一些标志功能 传入0即可
		   (sockaddr *)&siRecf,//用于接收发送方的信息,比如从哪个网络发过来的
		    &nNameLen
		    );
	
		if (nRet == SOCKET_ERROR)
		{
			printf("接收信息错误\\r\\n");
			WSACleanup();
			return 0;
		}

		std::cout << "收到客户端信息:" << aryBuf << std::endl;

		char aryBuf[MAXBYTE] = { "hello Server" };

		printf("请输入要发送的数据\\r\\n");

		std::cin >> aryBuf;
		nRet = sendto(sockServer, aryBuf, sizeof(aryBuf), 0, (sockaddr *)&siRecf, sizeof(siRecf));
		if (nRet == SOCKET_ERROR)
		{
			printf("发送数据错误 \\r\\n");
			WSACleanup();
			return 0;
		}

	}




	//关闭资源


	closesocket(sockServer);

	/* The Winsock DLL is acceptable. Proceed to use it. */

	/* Add network programming using Winsock here */

	/* then call WSACleanup when done using the Winsock dll */

	WSACleanup();



	return 0;

我们看下完整服务器的完整代码:

#include <iostream>

#include <Winsock2.h>
//导入动态库
#pragma comment(lib,"Ws2_32.lib")

int main()
{

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\\n", err);
		return 1;
	}

	/* Confirm that the WinSock DLL supports 2.2.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.2 in addition to 2.2, it will still return */
	/* 2.2 in wVersion since that is the version we      */
	/* requested.                                        */

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\\n");


	//(2)创建套接字对象,用于指定协议类型
	//https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
	SOCKET sockServer = socket(
		AF_INET,//指定协议是IPV4 还是IPV6.AF_INET是IPV4,AF_INET6是IPV6
		SOCK_DGRAM,//指定是TCP(SOCK_STREAM)或者UDP(SOCK_DGRAM)
		IPPROTO_UDP//指定具体的协议类型,如ICMP,IPPROTO_TCP或IPPROTO_UDP 
	);

	if (sockServer == INVALID_SOCKET)
	{
		printf("创建socket失败 \\r\\n");
		return 0;
	}

	//(3)绑定套接字所指定的端口
	sockaddr_in si;
	si.sin_family = AF_INET;
	//htons函数用于转化大小端,网络传输字节流统一采用大端
	//但在x86使用小端编码,所以利用htons屏蔽大小端
	si.sin_port = htons(0x5566);
	//inet_addr同上
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//绑定端口
	int nRet = bind(
		sockServer,//指定的协议
		(sockaddr *)&si,//指定的端口信息
		sizeof(si)
	);

	if (nRet == SOCKET_ERROR)
	{
		printf("绑定端口失败\\r\\n");
		WSACleanup();
		return 0;
	}


	//接收数据
	sockaddr_in siRecf;

	char aryBuf[MAXBYTE] = { 0 };
	int nNameLen = sizeof(siRecf);
	while (true)
	{
		nRet = recvfrom(sockServer, aryBuf, sizeof(aryBuf), 0, (sockaddr *)&siRecf, &nNameLen);
		if (nRet == SOCKET_ERROR)
		{
			printf("接收信息错误\\r\\n");
			WSACleanup();
			return 0;
		}

		std::cout << "收到客户端信息:" << aryBuf << std::endl;

		char aryBuf[MAXBYTE] = { "hello Server" };

		printf("请输入要发送的数据\\r\\n");

		std::cin >> aryBuf;
		nRet = sendto(sockServer, aryBuf, sizeof(aryBuf), 0, (sockaddr *)&siRecf, sizeof(siRecf));
		if (nRet == SOCKET_ERROR)
		{
			printf("发送数据错误 \\r\\n");
			WSACleanup();
			return 0;
		}

	}




	//关闭资源


	closesocket(sockServer);

	/* The Winsock DLL is acceptable. Proceed to use it. */

	/* Add network programming using Winsock here */

	/* then call WSACleanup when done using the Winsock dll */

	WSACleanup();



	return 0;

}

客户端代码也是差不多:


#include <iostream>

#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")

using namespace std;

int main()
{

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\\n", err);
		return 1;
	}

	/* Confirm that the WinSock DLL supports 2.2.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.2 in addition to 2.2, it will still return */
	/* 2.2 in wVersion since that is the version we      */
	/* requested.                                        */

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\\n");



	//https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
	SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	if (sockClient == INVALID_SOCKET)
	{
		printf("创建socket失败 \\r\\n");
		return 0;
	}

	sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(0x77988);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int nRet = bind(
		sockClient,
		(sockaddr *)&si,
		sizeof(si)
	);

	if (nRet == SOCKET_ERROR)
	{
		printf("绑定端口失败\\r\\n");
		WSACleanup();
		return 0;
	}
	//发送数据
	sockaddr_in siSever;

	siSever.sin_family = AF_INET;

	siSever.sin_port = htons(0x5566);//传入0 指定随机端口

	siSever.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");


	while (true)
	{

		char aryBuf[MAXBYTE] = { "hello Server" };
		
		printf("请输入要发送的数据\\r\\n");

		cin >> aryBuf;
		nRet = sendto(sockClient, aryBuf, sizeof(aryBuf), 0, (sockaddr *)&siSever, sizeof(siSever));
		if (nRet == SOCKET_ERROR)
		{
			printf("发送数据错误 \\r\\n");
			WSACleanup();
			return 0;
		}

		//接收数据
		sockaddr_in siRecf;

		char aryBuf2[MAXBYTE] = { 0 };
		int nNameLen = sizeof(siRecf);
		nRet = recvfrom(sockClient, aryBuf2, sizeof(aryBuf2), 0, (sockaddr *)&siRecf, &nNameLen);
		if (nRet == SOCKET_ERROR)
		{
			printf("接收信息错误\\r\\n");
			WSACleanup();
			return 0;
		}
		cout <<"收到服务端信息:" <<aryBuf2 << endl;
	}




	//关闭资源


	closesocket(sockClient);

	/* The Winsock DLL is acceptable. Proceed to use it. */

	/* Add network programming using Winsock here */

	/* then call WSACleanup when done using the Winsock dll */

	WSACleanup();

	return 0;
}

效果图:

上面输入 I come from China 服务端分开接收到, 是因为客户端cin没有一次性接收到一行,可以改用cin.getline

接下来看TCP例子就简单多了

TCP服务端:

// TCPServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<WinSock2.h>
#include<WS2tcpip.h>
#pragma comment(lib,"Ws2_32.lib")
//开启一个线程不断的处理收发消息
DWORD WINAPI HandleClientThreadFunc(LPVOID lpParam) {

	SOCKET sockClient = *((SOCKET*)lpParam);
	while (true)
	{
		//收发数据
		char buf[MAXBYTE] = { 0 };
		
		int iResult = recv(sockClient, buf, MAXBYTE, 0);

		if (iResult > 0)
			printf("Bytes received: %d   content %s \\n", iResult, buf);
		else if (iResult == 0) {
			printf("Connection closed\\n");
			return 0;
		}
		else {
			printf("recv failed: %d\\n", WSAGetLastError());
			return 0;
		}


		char aryBuffSend[] = { "server recv ok \\r\\n" };

		int nRet = send(sockClient, aryBuffSend, sizeof(aryBuffSend), 0);

		if (nRet == SOCKET_ERROR)
		{
			printf("发送错误\\r\\n");
		}
	}
	closesocket(sockClient);
}
int main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\\n", err);
		return 1;
	}

	/* Confirm that the WinSock DLL supports 2.2.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.2 in addition to 2.2, it will still return */
	/* 2.2 in wVersion since that is the version we      */
	/* requested.                                        */

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\\n");


	//创建socket
	SOCKET sockServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sockServer == INVALID_SOCKET)
	{
		printf("socket创建失败 ,请重启\\r\\n");
		return 0;
	}
	//绑定端口
	sockaddr_in siServer;
	siServer.sin_family = AF_INET;
	siServer.sin_port = htons(0x5566);
	int nRet = InetPton(AF_INET, "127.0.0.1", &siServer.sin_addr.s_addr);
	//等于1表示成功
	if (nRet != 1)
	{
		printf("错误");
		return 0;
	}

	nRet = bind(sockServer, (sockaddr*)&siServer, sizeof(siServer));


	if (nRet == SOCKET_ERROR)
	{
		printf("绑定端口失败,请重启 \\r\\n");
		return 0;
	}
	//监听
	nRet = listen(sockServer, SOMAXCONN);
	if (nRet != 0)
	{
		与 Win32 服务的进程间通信

STM32F103(二十五)完美解决USART发送接收floatu16u32数据

stm32 usb数据接收与数据发送程序流程分析

STM32CAN总线接口发送和接收数据

STM32 串口为啥只能接收发送的部分数据

Python代码从串口连续接收可变数据