windows网络编程(八)——重叠I/O+多线程实现简单的聊天(windows服务器端 windows客户端)

来源:互联网 发布:js获取json中的键值 编辑:程序博客网 时间:2024/05/19 17:55

1.客户端

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#include <process.h> #define BUF_SIZE 1000#define NAME_SIZE 20#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll  unsigned WINAPI SendMsg(void * arg);//发送信息函数unsigned WINAPI RecvMsg(void * arg);//接受信息函数void ErrorHandling(char * msg);//错误返回函数int haveread = 0;char NAME[50];//[名字]char ANAME[50];char msg[BUF_SIZE];//信息int main(int argc, char *argv[]){printf("请输入网名:");scanf("%s", NAME);WSADATA wsaData;SOCKET hSock;SOCKADDR_IN servAdr;HANDLE hSndThread, hRcvThread;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHandling("WSAStartup() error!");hSock = socket(PF_INET, SOCK_STREAM, 0);memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = inet_addr("127.0.0.1");servAdr.sin_port = htons(1234);if (connect(hSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)ErrorHandling("connect() error");int resultsend;puts("Welcome to joining our chatting room!\n");sprintf(ANAME, "[%s]", NAME);hSndThread =(HANDLE)_beginthreadex(NULL, 0, SendMsg, (void*)&hSock, 0, NULL);//写线程hRcvThread =(HANDLE)_beginthreadex(NULL, 0, RecvMsg, (void*)&hSock, 0, NULL);//读线程WaitForSingleObject(hSndThread, INFINITE);//等待线程结束WaitForSingleObject(hRcvThread, INFINITE);closesocket(hSock);WSACleanup();system("pause");return 0;}unsigned WINAPI SendMsg(void * arg)   // send thread main{SOCKET sock = *((SOCKET*)arg);char name_msg[NAME_SIZE + BUF_SIZE];char padd[2];fgets(padd, 2, stdin);//多余的'\n'printf("\n send message:");while (1){{fgets(msg, BUF_SIZE, stdin);if (!strcmp(msg, "q\n") || !strcmp(msg, "Q\n")){closesocket(sock);exit(0);}sprintf(name_msg, "[%s] %s", NAME, msg);char numofmsg = strlen(name_msg)+'0';char newmsg[100]; newmsg[0] = numofmsg; newmsg[1] = 0;//第一个字符表示消息的长度strcat(newmsg, name_msg);printf("信息的长度:%d", strlen(newmsg));int result = send(sock, newmsg, strlen(newmsg), 0);printf("客户端发送的消息:%s\n", newmsg);if (result == -1)return -1;//发送错误}}return NULL;}unsigned WINAPI RecvMsg(void * arg)  // read thread main{SOCKET sock = *((SOCKET*)arg);char name_msg[NAME_SIZE + BUF_SIZE];int str_len = 0;while (1){{char lyfstr[1000] = { 0 };int totalnum = 0;str_len = recv(sock, name_msg, 1, 0);//读取第一个字符!获取消息的长度name_msg[str_len] = 0;strcat(lyfstr, name_msg);if (str_len == -1)//读取错误{printf("return -1\n");return -1;}if (str_len == 0)//读取结束{printf("return 0\n");return 0;//读取结束}totalnum = name_msg[0]-'0';int count = 0;do{str_len = recv(sock, name_msg, 1, 0);name_msg[str_len] = 0;if (str_len == -1)//读取错误{printf("return -1\n");return -1;}if (str_len == 0){printf("return 0\n");return 0;//读取结束}strcat(lyfstr, name_msg);count = str_len+count;} while (count < totalnum);lyfstr[count] = '\0';printf("\n");strcat(lyfstr, "\n");fputs(lyfstr, stdout);printf(" send message:");fflush(stdout);memset(name_msg, 0, sizeof(char));}}return NULL;}void ErrorHandling(char * msg){fputs(msg, stderr);fputc('\n', stderr);exit(1);}





2.服务器端

#include <stdio.h>#include <stdlib.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll  #define BUF_SIZE 1024void CALLBACK ReadCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);void CALLBACK WriteCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);void ErrorHandling(char *message);typedef struct{SOCKET hClntSock;char buf[BUF_SIZE];WSABUF wsaBuf;} PER_IO_DATA, *LPPER_IO_DATA;SOCKET ALLCLIENT[100];//所有客户端int CONNECNUM = 0;//计数LPWSAOVERLAPPED overlap[100];//所有客户端的相关结构int overcount = 0;int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hLisnSock, hRecvSock;SOCKADDR_IN lisnAdr, recvAdr;LPWSAOVERLAPPED lpOvLp;DWORD recvBytes=0;LPPER_IO_DATA hbInfo;u_long mode = 1;DWORD  flagInfo = 0;int recvAdrSz=0;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHandling("WSAStartup() error!");hLisnSock = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);ioctlsocket(hLisnSock, FIONBIO, &mode);   // for non-blocking socket(非阻塞套接字)memset(&lisnAdr, 0, sizeof(lisnAdr));lisnAdr.sin_family = AF_INET;lisnAdr.sin_addr.s_addr = htonl(INADDR_ANY);lisnAdr.sin_port = htons(1234);if (bind(hLisnSock, (SOCKADDR*)&lisnAdr, sizeof(lisnAdr)) == SOCKET_ERROR)ErrorHandling("bind() error");if (listen(hLisnSock, 5) == SOCKET_ERROR)ErrorHandling("listen() error");recvAdrSz = sizeof(recvAdr);while (1){SleepEx(100, TRUE);    // for alertable wait state(设置状态)hRecvSock = accept(hLisnSock, (SOCKADDR*)&recvAdr, &recvAdrSz);if (hRecvSock == INVALID_SOCKET){if (WSAGetLastError() == WSAEWOULDBLOCK)//只表示无连接continue;elseErrorHandling("accept() error");}ALLCLIENT[CONNECNUM++] = hRecvSock;puts("Client connected.....");lpOvLp = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));overlap[overcount++] = lpOvLp;//存入数组memset(lpOvLp, 0, sizeof(WSAOVERLAPPED));hbInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));hbInfo->hClntSock = (DWORD)hRecvSock;(hbInfo->wsaBuf).buf = hbInfo->buf;(hbInfo->wsaBuf).len = BUF_SIZE;lpOvLp->hEvent = (HANDLE)hbInfo;//特殊类型转换if (WSARecv(hRecvSock, &(hbInfo->wsaBuf),1, &recvBytes, &flagInfo, lpOvLp, ReadCompRoutine)==SOCKET_ERROR)if (WSAGetLastError() == WSA_IO_PENDING){printf("接收数据中.");}}closesocket(hRecvSock);closesocket(hLisnSock);WSACleanup();return 0;}void CALLBACK ReadCompRoutine(//参数:(错误信息,实际收发字节数,WSA*的lpOverlapped参数,特性信息或0)DWORD dwError, DWORD szRecvBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags){LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);//类型转回SOCKET hSock = hbInfo->hClntSock;LPWSABUF bufInfo = &(hbInfo->wsaBuf);DWORD sentBytes;if (szRecvBytes == 0){int i = 0;while (ALLCLIENT[i] != hSock)i++;ALLCLIENT[i] = -1;closesocket(hSock);free(lpOverlapped->hEvent); free(lpOverlapped);puts("Client disconnected.....");}else    // echo!{bufInfo->len = szRecvBytes;//存储实际接收到的字节数,在A发送一条,B发送一条,A再发送一条信息时接受到的信息会出错,不知道原因??int k = 0;for (; k < CONNECNUM; k++){if (ALLCLIENT[k] != -1){int result = 0;result = WSASend(ALLCLIENT[k], bufInfo, 1, &sentBytes, 0, overlap[k], WriteCompRoutine);}}}}void CALLBACK WriteCompRoutine(//参数:(错误信息,实际收发字节数,WSA*的lpOverlapped参数,特性信息或0)DWORD dwError, DWORD szSendBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags){LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);SOCKET hSock = hbInfo->hClntSock;LPWSABUF bufInfo = &(hbInfo->wsaBuf);DWORD recvBytes=0;DWORD flagInfo = 0;int result = WSARecv(hSock, bufInfo,1, &recvBytes, &flagInfo, lpOverlapped, ReadCompRoutine);}void ErrorHandling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);}




3.结果



阅读全文
0 0
原创粉丝点击