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实现聊天服务相关推荐

  1. 老雷socket编程之PHP利用socket扩展实现聊天服务

    老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streams sockets socket_create(AF ...

  2. 基于Trtc的内贸站视频聊天服务

    基于Trtc的内贸站视频聊天服务分享 说到视频聊天,大家第一个想到的是啥,QQ! 其实最早的视频聊天工具应该是 : Netmeeting(我能找到的最早聊天工具) Netmeeting是Windows ...

  3. D1net阅闻:亚马逊引入Biba的员工和专利,据称计划推出新的视频聊天服务

    亚马逊引入Biba的员工和专利,据称计划推出新的视频聊天服务 亚马逊收购Twitch和Elemental Technologies似乎只是公司战略的两个部分,计划通过收购进行更深入的视频服务.去年,亚 ...

  4. [导入]Web聊天:八个优秀的网页聊天服务

    可能很多人认为在网页上进行沟通是无益的,当然,我们做为个人博客又或个人站点,自然是有充分的自由,我爱聊不聊,没人管得着.但是有个问题我已经思考了很久,为什么国内那么多的垃圾在线聊天服务商能存活呢?他们 ...

  5. 关于启动聊天服务(Linux系统)--龙兵AI名片

    Linux系统环境检测 Linux系统可以使用以下脚本测试本机PHP环境是否满足WorkerMan运行要求. curl -Ss http://www.workerman.net/check.php | ...

  6. Qt学习心得之网络编程简单的局域网聊天服务端建立

    学而不思则罔,思而不学则殆.学习和思考是相辅相成的,通过这几天对网络编程的学习,收获颇丰.接下来我将利用Qt做的一个以TcpIp协议为传输方式的简单的局域网聊天服务端与大家分享下: 首先谈谈我个人对T ...

  7. IM即时通讯设计----聊天服务(附源码)

    来源:微信公众号「编程学习基地」 文章目录 IM即时通信程序设计 IM即时通讯 设计一款高并发聊天服务需要注意什么 如何设计可靠的消息处理服务 什么是粘包 什么是半包 解决粘包和半包 IM通信协议 应 ...

  8. linux写聊天程序,轻易实现基于linux或win运行的聊天服务端程序

    对于不了解网络编程的开发人员来说,编写一个良好的服务端通讯程序是一件比较麻烦的事情.然而通过EC这个免费组件你可以非常简单地构建一个基于linux或win部署运行的网络服务程序.这种便利性完全得益于m ...

  9. 在ubuntu上实现基于webrtc的多人在线视频聊天服务

    最近研究webrtc视频直播技术,网上找了些教程最终都不太能顺利跑起来的,可能是文章写的比较老,使用的一些开源组件已经更新了,有些配置已经不太一样了,所以按照以前的步骤会有问题.折腾了一阵终于跑起来了 ...

  10. 跨境电商如何通过实时聊天服务改善客户体验?

    关键词:跨境电商,实时聊天,客户服务 实时聊天是客户从跨境电商卖家那里获得即时帮助的沟通渠道.它促进了客户与跨境电商品牌人工代理之间的实时1:1交互,以解决客户问题. 企业通常在其网站上嵌入实时聊天支 ...

最新文章

  1. sturts2 单上传、多上传、下载例子
  2. 命令行选项“/source-charset”与预编译头不一致
  3. mysql备份与还原-mysqldump备份、mysql与source还原
  4. mahout in Action2.2-给用户推荐图书(2)-分析对用户推荐书目的结果
  5. LOAM_velodyne学习(三)
  6. CF455B A Lot of Games
  7. (数据科学学习手札03)Python与R在随机数生成上的异同
  8. mac docker 共享_如何在Docker for Mac中加快共享文件访问
  9. 打扰了!MacBook Pro 16英寸国行版正式开售:顶配46421元
  10. java 源树_【Java源码】树-概述
  11. 千呼万唤始出来的IDEA笔记插件mdNote
  12. 阿里云视频点播解密DecryptKMSDataKeyRequest爬坑
  13. pathon的安装与环境部署,数据类型
  14. android 9.x MTK平台讯飞输入法重启被卸载
  15. PgAdmin3 F7
  16. 群论基础速成(6):五大著名群族
  17. c#语言猜数字游戏,C#实现猜数字游戏
  18. Ghost超级技巧一家亲
  19. STM32闭环步进电机驱动器方案,原理图,源码,PCB
  20. 指定播放文件-视频监控系统程序

热门文章

  1. python蚁群算法可视化_蚁群算法原理及其实现(python)
  2. 启动mysql显示FAILED_转mysql提示mysql daemon failed to start 启动不了的解决办法
  3. 关于安全校验代码的一些心得
  4. Nginx源码分析 - 实战篇 - 编写一个自定义的模块(24)
  5. TCP三次握手和四次挥手详解 --- 转载
  6. 虚函数和虚析构函数的实现原理--虚函数表
  7. [转载]Java程序占用 CPU 过高怎么排查
  8. mysql默认dba_DBA 基本常识 - 安装完 MySQL 后必须调整的 10 项配置 - iTeknical
  9. 【渝粤教育】国家开放大学2018年秋季 7389-22T劳动与社会保障法 参考试题
  10. 【渝粤教育】国家开放大学2018年春季 8647-21T工程经济与管理 参考试题