WSA重叠IO

2024-09-06 14:44
文章标签 io 重叠 wsa

本文主要是介绍WSA重叠IO,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

服务端:


#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>#define PORT 6000
#define IP_ADDRESS "127.0.0.1"
#define MSGSIZE 1024class PerSocketData
{
public:WSAOVERLAPPED overlap;WSABUF buffer;char szMessage[MSGSIZE];DWORD NumberOfBytesRecvd;DWORD flags;
};class SocketListWithIOEvent
{
public:SOCKET socketArray[MAXIMUM_WAIT_OBJECTS];PerSocketData* overLappedData[MAXIMUM_WAIT_OBJECTS];WSAEVENT eventArray[MAXIMUM_WAIT_OBJECTS];int totalConn;
public:SocketListWithIOEvent(){totalConn = 0;for (size_t i = 0; i < MAXIMUM_WAIT_OBJECTS; i++){socketArray[i] = 0;overLappedData[i] = NULL;eventArray[i] = NULL;}}PerSocketData* insetSocket(SOCKET s){socketArray[totalConn] = s;overLappedData[totalConn] = (PerSocketData*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PerSocketData));overLappedData[totalConn]->buffer.len = MSGSIZE;overLappedData[totalConn]->buffer.buf = overLappedData[totalConn]->szMessage;overLappedData[totalConn]->overlap.hEvent = WSACreateEvent();eventArray[totalConn] = overLappedData[totalConn]->overlap.hEvent;return 	overLappedData[totalConn++];}void deleteSocket(int index){closesocket(socketArray[index]);WSACloseEvent(eventArray[index]);HeapFree(GetProcessHeap(), 0, overLappedData[index]);if (index < totalConn - 1){socketArray[index] = socketArray[totalConn - 1];overLappedData[index] = overLappedData[totalConn - 1];eventArray[index] = eventArray[totalConn - 1];}overLappedData[--totalConn] = NULL;}
};//当main的while里面插入的sock,有事件发生时,就不进行continue并往下执行.
//假如一个新的客户端连接并发送了数据:123,main函数里面的while循环里面插入了这个新的客户端,并调用WSArecv接受数据:123.
//所以workThread线程,有事件发生了(接受道数据:123),然后手动复位,通过WSAGetOverlappedResult获取收到的数据,并将数据原封不动的发给客户端.
//然后又调用非阻塞性的WSArecv接受数据,如果调用WSArecv瞬间有数据,那么就又重复以上步骤,如果调用WSArecv瞬间数据还没收到,则WSArecv不管直接返回(会在后台挂起,等待数据到达,有点类似于自己开了个线程,一直等待执行,有数据返回并关闭线程),WSAWaitForMultipleEvents就没有事件发生,就又进行continue,循环等待事件发生.
DWORD WINAPI workThread(LPVOID lpParam)
{int nRes;int nCurrentIndex;DWORD cbTransFerred;SocketListWithIOEvent* sockList = (SocketListWithIOEvent*)lpParam;while (true){nRes = WSAWaitForMultipleEvents(sockList->totalConn, sockList->eventArray, FALSE, 1000, FALSE);if (nRes == WSA_WAIT_FAILED || nRes == WSA_WAIT_TIMEOUT){continue;}nCurrentIndex = nRes - WSA_WAIT_EVENT_0;WSAResetEvent(sockList->eventArray[nCurrentIndex]);WSAGetOverlappedResult(sockList->socketArray[nCurrentIndex],&sockList->overLappedData[nCurrentIndex]->overlap,&cbTransFerred,TRUE,&sockList->overLappedData[sockList->totalConn]->flags);if (cbTransFerred == 0){printf("Client 断开链接!\r\n");sockList->deleteSocket(nCurrentIndex);}else{std::cout << sockList->overLappedData[nCurrentIndex]->szMessage << std::endl;send(sockList->socketArray[nCurrentIndex], sockList->overLappedData[nCurrentIndex]->szMessage, cbTransFerred, 0);WSARecv(sockList->socketArray[nCurrentIndex],&sockList->overLappedData[nCurrentIndex]->buffer,1,&sockList->overLappedData[nCurrentIndex]->NumberOfBytesRecvd,&sockList->overLappedData[nCurrentIndex]->flags,&sockList->overLappedData[nCurrentIndex]->overlap, NULL);}}return 0;
}int main()
{WSADATA wsa;int nRes = WSAStartup(MAKEWORD(2, 2), &wsa);if (nRes != 0){printf("WSAStartup Error!\r\n");return -1;}SOCKET serverSocket;serverSocket = socket(AF_INET, SOCK_STREAM, 0);if (serverSocket == INVALID_SOCKET){printf("socket Error!\r\n");return -1;}sockaddr_in serverAddr;sockaddr_in clientAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(PORT);serverAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);nRes = bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));if (nRes != 0){printf("bind Error!\r\n");return -1;}nRes = listen(serverSocket, 10);if (nRes != 0){printf("listen Error!\r\n");return -1;}printf("Server Runing!\r\n");int addrLen = sizeof(clientAddr);SOCKET sockConn;SocketListWithIOEvent socketList;HANDLE hThread = CreateThread(NULL, 0, workThread, &socketList, 0, NULL);if (hThread == NULL){printf("CreareThread Failed!\r\n");}CloseHandle(hThread);//这里面,每一个新连接的客服端的第一次数据,是此处while循环里面WSARecv接收数据,后面的数据全部走线程里面接收,如果没有新的客服端连接,此处while循环里面的accept函数将阻塞,不往下执行,一直等待新的客服端连接,当然上一个已经连接的客服端已经由线程一直接受数据while (true){sockConn = accept(serverSocket, (sockaddr*)&clientAddr, &addrLen);if (sockConn == INVALID_SOCKET){printf("accept Failed!\r\n");return -1;}std::cout << "Clinet link:" << inet_ntoa(clientAddr.sin_addr) << ":" << clientAddr.sin_port << std::endl;PerSocketData* overLappedData = socketList.insetSocket(sockConn);WSARecv(sockConn, &overLappedData->buffer, 1, &overLappedData->NumberOfBytesRecvd, &overLappedData->flags, &overLappedData->overlap, NULL);}closesocket(serverSocket);WSACleanup();return 0;
}

客服端:


#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>
#include <process.h>void recv(PVOID pt)
{SOCKET sHost = *((SOCKET*)pt);while (true){char buf[64]{ 0 };int nRes = recv(sHost, buf, sizeof(buf), 0);if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK){Sleep(1000);continue;}else if (nError == WSAETIMEDOUT || nError == WSAENETDOWN || nError == WSAECONNRESET){printf("revc failed!\r\n");closesocket(sHost);WSACleanup();return;}}Sleep(100);printf("\r\nrecv:%s", buf);printf("\r\ninput your buffer:\r\n");}
}int main()
{WSADATA wsa;SOCKET sHost;SOCKADDR_IN serverAddr;int nRes;char buf[64]{ 0 };nRes = WSAStartup(MAKEWORD(2, 2), &wsa);if (nRes != 0){printf("WSAStartup Error!\r\n");return -1;}sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(6000);serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");int sServerAddrlen = sizeof(serverAddr);int iMode = 1;nRes = ioctlsocket(sHost, FIONBIO, (u_long*)&iMode);if (nRes == SOCKET_ERROR){printf("ioctlsocket error!\r\n");WSACleanup();return -1;}printf("clinet runing...\r\n");while (true){nRes = connect(sHost, (SOCKADDR*)&serverAddr, sizeof(serverAddr));if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK || nError == WSAEINVAL){Sleep(1);printf("check!\r\n");continue;}else if (nError == WSAEISCONN){break;}else{printf("connect failed!\r\n");closesocket(sHost);WSACleanup();return -1;}}}unsigned long lThreadid = _beginthread(recv, 0, &sHost);printf("input data:\r\n");while (true){char szBuffer[1024]{ 0 };std::cin >> szBuffer;while (true){nRes = send(sHost, szBuffer, strlen(szBuffer), 0);if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK){Sleep(5);continue;}else{printf("send failed!\r\n");closesocket(sHost);WSACleanup();return -1;}}break;}}return 0;
}

这篇关于WSA重叠IO的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142304

相关文章

Java IO 操作——个人理解

之前一直Java的IO操作一知半解。今天看到一个便文章觉得很有道理( 原文章),记录一下。 首先,理解Java的IO操作到底操作的什么内容,过程又是怎么样子。          数据来源的操作: 来源有文件,网络数据。使用File类和Sockets等。这里操作的是数据本身,1,0结构。    File file = new File("path");   字

springboot体会BIO(阻塞式IO)

使用springboot体会阻塞式IO 大致的思路为: 创建一个socket服务端,监听socket通道,并打印出socket通道中的内容。 创建两个socket客户端,向socket服务端写入消息。 1.创建服务端 public class RedisServer {public static void main(String[] args) throws IOException {

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

android java.io.IOException: open failed: ENOENT (No such file or directory)-api23+权限受权

问题描述 在安卓上,清单明明已经受权了读写文件权限,但偏偏就是创建不了目录和文件 调用mkdirs()总是返回false. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_E

JavaEE-文件操作与IO

目录 1,两种路径 二,两种文件 三,文件的操作/File类: 1)文件系统操作 File类 2)文件内容操作(读文件,写文件) (1)打开文件 (2)关闭文件 (3)读文件/InputStream (4)写文件/OutputStream (5)读文件/reader (6)写文件/writer (7)Scanner 四,练习: 1,两种路径 1)绝对路径

Python---文件IO流及对象序列化

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 前言 前文模块中提到加密模块,本文将终点介绍加密模块和文件流。 一、文件流和IO流概述         在Python中,IO流是用于输入和输出数据的通道。它可以用于读取输入数据或将数据写入输出目标。IO流可以是标准输入/输出流(stdin和stdout),也可以是文件流,网络流等。

标准IO与系统IO

概念区别 标准IO:(libc提供) fopen fread fwrite 系统IO:(linux系统提供) open read write 操作效率 因为内存与磁盘的执行效率不同 系统IO: 把数据从内存直接写到磁盘上 标准IO: 数据写到缓存,再刷写到磁盘上

linux基础IO——动静态库——进程编址、进程执行、动态库加载

前言:本节内容为基础IO部分的最后一节, 主要是为了讲一下动静态库里面的动态库如何加载到内存, 动态库的地址等等。 但是,这些内容牵扯到了程序的编址, 程序的加载, 进程的执行等等知识点, 所以,我们会从程序的编址讲起, 一直到进程的执行, 以及动态库加载结束。         ps:本节内容涉及到了进程地址空间, 磁盘的内容, 建议友友们了解相关知识后再来观看。 目录

mybatis错误——java.io.IOException Could not find resource comxxxxxxMapper.xml

在学习Mybatis的时候,参考网上的教程进行简单demo的搭建,配置的没有问题,然后出现了下面的错误! Exception in thread "main" java.lang.RuntimeException: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause:

day09-IO-字符流其它流

一、字符流 字符流(只能做文本文件的处理)字符输入流 Reader--FileReader字符输出流 Writer--FileWriter​使用文件字符输入流的好处:读取中文不会出现乱码问题 1.1 字符输入流 构造器说明public FileReader (File file)创建字符输入流管道与源文件接通public FileReader(String pathname)创建字