IOCP实现聊天服务
IOCP实现聊天服务
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4996)
#define BUF_SIZE 1024
#define READ 1
#define WRITE 2
typedef struct // socket info
{
SOCKET hClntSock;
SOCKADDR_IN clntAddr;
} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
typedef struct // buffer info
{
OVERLAPPED overlapped;
WSABUF wsaBuf;
char buffer[BUF_SIZE];
int rwMode; // READ or WRITE
} PER_IO_DATA, *LPPER_IO_DATA;
typedef struct
{
LPPER_HANDLE_DATA lpSockInfoSet[BUF_SIZE];
DWORD numofsock;
} SOCK_DATA_SET, *LPSOCK_DATA_SET;
SOCK_DATA_SET sockSet;
BOOL AddSock(LPPER_HANDLE_DATA lpSockInfo);
BOOL DeleteSock(LPPER_HANDLE_DATA lpSockInfo);
BOOL SendToAll(LPPER_IO_DATA lpIOInfo, DWORD bytesTrans);
void ErrorHandling(const char* message);
DWORD WINAPI IOHandlingThread(LPVOID CompletionPortIO);
void CreateNewWriteInfoFromReadInfo(LPPER_IO_DATA* lpSrc, LPPER_IO_DATA* lpDes, DWORD bytesTrans);
int main(int argc, char* argv[])
{
memset(&sockSet, 0, sizeof(SOCK_DATA_SET));
WSADATA wsaData;
HANDLE hComPort;
LPPER_HANDLE_DATA lpSockInfo;
LPPER_IO_DATA lpIOInfo;
SYSTEM_INFO sysInfo;
SOCKET hListenSock, hClientSock;
SOCKADDR_IN listenAddr, clientAddr;
int addrSize;
DWORD recvBytes, flags = 0;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() Error");
if (argc != 2)
{
printf("Usage: %s <port> \n", argv[0]);
exit(1);
}
hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
GetSystemInfo(&sysInfo);
for (int i = 0; i < sysInfo.dwNumberOfProcessors; i++)
_beginthreadex(NULL, 0, IOHandlingThread, (LPVOID)hComPort, 0, NULL);
hListenSock = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
memset(&listenAddr, 0, sizeof(listenAddr));
listenAddr.sin_family = AF_INET;
listenAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
listenAddr.sin_port = htons(atoi(argv[1]));
if (bind(hListenSock, (SOCKADDR*)&listenAddr, sizeof(listenAddr)) != 0)
ErrorHandling("bind() Error");
if (listen(hListenSock, 5) != 0)
ErrorHandling("listen() Error");
while (1)
{
addrSize = sizeof(clientAddr);
hClientSock = accept(hListenSock, (SOCKADDR*)&clientAddr, &addrSize);
if (hClientSock == INVALID_SOCKET)
ErrorHandling("accept() error");
lpSockInfo = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
lpSockInfo->hClntSock = hClientSock;
lpSockInfo->clntAddr = clientAddr;
CreateIoCompletionPort((HANDLE)hClientSock, hComPort, (DWORD)lpSockInfo, 0);
lpIOInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
memset(&(lpIOInfo->overlapped), 0, sizeof(PER_IO_DATA));
lpIOInfo->wsaBuf.len = BUF_SIZE;
lpIOInfo->wsaBuf.buf = lpIOInfo->buffer;
lpIOInfo->rwMode = READ;
WSARecv(lpSockInfo->hClntSock, &(lpIOInfo->wsaBuf), 1, &recvBytes, &flags, &(lpIOInfo->overlapped), NULL);
AddSock(lpSockInfo);
}
return 0;
}
BOOL AddSock(LPPER_HANDLE_DATA lpSockInfo)
{
int numofsock = sockSet.numofsock;
sockSet.lpSockInfoSet[numofsock] = lpSockInfo;
sockSet.numofsock++;
return TRUE;
}
BOOL DeleteSock(LPPER_HANDLE_DATA lpSockInfo)
{
int numofsock = sockSet.numofsock;
LPPER_HANDLE_DATA* sockInfoArr = sockSet.lpSockInfoSet;
for (int i = 0; i < numofsock; i++)
{
if (lpSockInfo == sockInfoArr[i])
{
for (int next = i + 1; next < numofsock; next++)
sockInfoArr[i] = sockInfoArr[next];
sockSet.numofsock--;
}
}
return TRUE;
}
void ErrorHandling(const char* message)
{
fprintf(stderr, "%s, Error Code %d \n", message, WSAGetLastError());
exit(1);
}
DWORD WINAPI IOHandlingThread(LPVOID CompletionPortIO)
{
HANDLE hComPort = (HANDLE)CompletionPortIO;
SOCKET sock;
DWORD bytesTrans;
LPPER_IO_DATA lpIOInfo;
LPPER_HANDLE_DATA lpSockInfo;
DWORD flags = 0;
while (1)
{
GetQueuedCompletionStatus(hComPort, &bytesTrans, (LPDWORD)& lpSockInfo, (LPOVERLAPPED*)& lpIOInfo, INFINITE);
sock = lpSockInfo->hClntSock;
if (lpIOInfo->rwMode == READ)
{
puts("message recvived");
if (bytesTrans == 0) // EOF
{
DeleteSock(lpSockInfo);
free(lpSockInfo);
free(lpIOInfo);
continue;
}
SendToAll(lpIOInfo, bytesTrans);
lpIOInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
memset(&(lpIOInfo->overlapped), 0, sizeof(PER_IO_DATA));
lpIOInfo->wsaBuf.len = BUF_SIZE;
lpIOInfo->wsaBuf.buf = lpIOInfo->buffer;
lpIOInfo->rwMode = READ;
WSARecv(sock, &(lpIOInfo->wsaBuf), 1, NULL, &flags, &(lpIOInfo->overlapped), NULL);
}
else
{
puts("message send!");
free(lpIOInfo);
}
}
return 0;
}
BOOL SendToAll(LPPER_IO_DATA lpIOInfo, DWORD bytesTrans)
{
LPPER_IO_DATA lpReadInfo = lpIOInfo;
LPPER_IO_DATA lpWriteInfo;
DWORD sendBytes;
for (int i = 0; i < sockSet.numofsock; i++)
{
SOCKET sock = sockSet.lpSockInfoSet[i]->hClntSock;
CreateNewWriteInfoFromReadInfo(&lpReadInfo, &lpWriteInfo, bytesTrans);
WSASend(sock, &(lpWriteInfo->wsaBuf), 1, &sendBytes, 0, &(lpWriteInfo->overlapped), NULL);
}
return TRUE;
}
void CreateNewWriteInfoFromReadInfo(LPPER_IO_DATA* lpSrc, LPPER_IO_DATA* lpDes, DWORD bytesTrans)
{
*lpDes = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
LPPER_IO_DATA src = *lpSrc;
LPPER_IO_DATA des = *lpDes;
memcpy(des, src, sizeof(PER_IO_DATA));
des->wsaBuf.buf = des->buffer;
des->wsaBuf.len = bytesTrans;
des->rwMode = WRITE;
}
客户端实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4996)
#define BUF_SIZE 100
#define NAME_SIZE 20
unsigned WINAPI SendMsg(void * arg);
unsigned WINAPI RecvMsg(void * arg);
void ErrorHandling(char * msg);
char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSock;
SOCKADDR_IN servAddr;
HANDLE hSendThread, hRecvThread;
if (argc != 4)
{
printf("Usage: %s <IP> <port> <name> \n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error");
sprintf(name, "[%s]", argv[3]);
hSock = socket(PF_INET, SOCK_STREAM, 0);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]);
servAddr.sin_port = htons(atoi(argv[2]));
if (connect(hSock, (SOCKADDR*)& servAddr, sizeof(servAddr)) != 0)
ErrorHandling("connect() error");
hSendThread = (HANDLE)_beginthreadex(NULL, 0, SendMsg, (void*)&hSock, 0, NULL);
hRecvThread = (HANDLE)_beginthreadex(NULL, 0, RecvMsg, (void*)&hSock, 0, NULL);
WaitForSingleObject(hSendThread, INFINITE);
WaitForSingleObject(hRecvThread, INFINITE);
closesocket(hSock);
WSACleanup();
return 0;
}
unsigned WINAPI SendMsg(void* arg)
{
SOCKET hSock = *((SOCKET*)arg);
char nameMsg[NAME_SIZE+BUF_SIZE];
while (1)
{
fgets(msg, BUF_SIZE, stdin);
if (!strcmp(msg, "q\n") || !strcmp(msg, "Q\n"))
{
closesocket(hSock);
exit(0);
}
sprintf(nameMsg, "%s %s", name, msg);
send(hSock, nameMsg, strlen(nameMsg), 0);
}
return 0;
}
unsigned WINAPI RecvMsg(void* arg)
{
SOCKET hSock = *((SOCKET*)arg);
char nameMsg[NAME_SIZE+BUF_SIZE];
int strLen;
while (1)
{
strLen = recv(hSock, nameMsg, NAME_SIZE+BUF_SIZE-1, 0);
if (strLen == -1)
return -1;
nameMsg[strLen] = '\0';
fputs(nameMsg, stdout);
}
return 0;
}
void ErrorHandling(char* msg)
{
fprintf(stderr, "%s, Error Code %d \n", msg, WSAGetLastError());
exit(1);
}
转载于:https://www.cnblogs.com/freesfu/p/10972597.html
IOCP实现聊天服务相关推荐
- 老雷socket编程之PHP利用socket扩展实现聊天服务
老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streams sockets socket_create(AF ...
- 基于Trtc的内贸站视频聊天服务
基于Trtc的内贸站视频聊天服务分享 说到视频聊天,大家第一个想到的是啥,QQ! 其实最早的视频聊天工具应该是 : Netmeeting(我能找到的最早聊天工具) Netmeeting是Windows ...
- D1net阅闻:亚马逊引入Biba的员工和专利,据称计划推出新的视频聊天服务
亚马逊引入Biba的员工和专利,据称计划推出新的视频聊天服务 亚马逊收购Twitch和Elemental Technologies似乎只是公司战略的两个部分,计划通过收购进行更深入的视频服务.去年,亚 ...
- [导入]Web聊天:八个优秀的网页聊天服务
可能很多人认为在网页上进行沟通是无益的,当然,我们做为个人博客又或个人站点,自然是有充分的自由,我爱聊不聊,没人管得着.但是有个问题我已经思考了很久,为什么国内那么多的垃圾在线聊天服务商能存活呢?他们 ...
- 关于启动聊天服务(Linux系统)--龙兵AI名片
Linux系统环境检测 Linux系统可以使用以下脚本测试本机PHP环境是否满足WorkerMan运行要求. curl -Ss http://www.workerman.net/check.php | ...
- Qt学习心得之网络编程简单的局域网聊天服务端建立
学而不思则罔,思而不学则殆.学习和思考是相辅相成的,通过这几天对网络编程的学习,收获颇丰.接下来我将利用Qt做的一个以TcpIp协议为传输方式的简单的局域网聊天服务端与大家分享下: 首先谈谈我个人对T ...
- IM即时通讯设计----聊天服务(附源码)
来源:微信公众号「编程学习基地」 文章目录 IM即时通信程序设计 IM即时通讯 设计一款高并发聊天服务需要注意什么 如何设计可靠的消息处理服务 什么是粘包 什么是半包 解决粘包和半包 IM通信协议 应 ...
- linux写聊天程序,轻易实现基于linux或win运行的聊天服务端程序
对于不了解网络编程的开发人员来说,编写一个良好的服务端通讯程序是一件比较麻烦的事情.然而通过EC这个免费组件你可以非常简单地构建一个基于linux或win部署运行的网络服务程序.这种便利性完全得益于m ...
- 在ubuntu上实现基于webrtc的多人在线视频聊天服务
最近研究webrtc视频直播技术,网上找了些教程最终都不太能顺利跑起来的,可能是文章写的比较老,使用的一些开源组件已经更新了,有些配置已经不太一样了,所以按照以前的步骤会有问题.折腾了一阵终于跑起来了 ...
- 跨境电商如何通过实时聊天服务改善客户体验?
关键词:跨境电商,实时聊天,客户服务 实时聊天是客户从跨境电商卖家那里获得即时帮助的沟通渠道.它促进了客户与跨境电商品牌人工代理之间的实时1:1交互,以解决客户问题. 企业通常在其网站上嵌入实时聊天支 ...
最新文章
- sturts2 单上传、多上传、下载例子
- 命令行选项“/source-charset”与预编译头不一致
- mysql备份与还原-mysqldump备份、mysql与source还原
- mahout in Action2.2-给用户推荐图书(2)-分析对用户推荐书目的结果
- LOAM_velodyne学习(三)
- CF455B A Lot of Games
- (数据科学学习手札03)Python与R在随机数生成上的异同
- mac docker 共享_如何在Docker for Mac中加快共享文件访问
- 打扰了!MacBook Pro 16英寸国行版正式开售:顶配46421元
- java 源树_【Java源码】树-概述
- 千呼万唤始出来的IDEA笔记插件mdNote
- 阿里云视频点播解密DecryptKMSDataKeyRequest爬坑
- pathon的安装与环境部署,数据类型
- android 9.x MTK平台讯飞输入法重启被卸载
- PgAdmin3 F7
- 群论基础速成(6):五大著名群族
- c#语言猜数字游戏,C#实现猜数字游戏
- Ghost超级技巧一家亲
- STM32闭环步进电机驱动器方案,原理图,源码,PCB
- 指定播放文件-视频监控系统程序
热门文章
- python蚁群算法可视化_蚁群算法原理及其实现(python)
- 启动mysql显示FAILED_转mysql提示mysql daemon failed to start 启动不了的解决办法
- 关于安全校验代码的一些心得
- Nginx源码分析 - 实战篇 - 编写一个自定义的模块(24)
- TCP三次握手和四次挥手详解 --- 转载
- 虚函数和虚析构函数的实现原理--虚函数表
- [转载]Java程序占用 CPU 过高怎么排查
- mysql默认dba_DBA 基本常识 - 安装完 MySQL 后必须调整的 10 项配置 - iTeknical
- 【渝粤教育】国家开放大学2018年秋季 7389-22T劳动与社会保障法 参考试题
- 【渝粤教育】国家开放大学2018年春季 8647-21T工程经济与管理 参考试题