win32 基础数据发送与接收
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32 基础数据发送与接收相关的知识,希望对你有一定的参考价值。
前言
在Win32
中发送基础网络数据相比起其他语言如java可能比较复杂。
大致流程:
- 导入
Ws2_32.lib
- 根据一定规范初始化
Ws2_32.lib
- 创建套接字对象,用于指定协议类型
- 绑定套接字所指定的端口
- 调用收发函数
- 资源回收
- (1)导入
Ws2_32.lib
有两种方式指示导入动态库
- 编译宏指示连接器
#pragma comment(lib,"Ws2_32.lib")
VS
中配置
- (2)初始化
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");
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 服务的进程间通信