17-实现多线程群聊服务器

实现多线程群聊服务器

1.设计思路

  • 对于每一个上线的客户端,服务端会起一个线程去维护

  • 将消息转发给全部客户端

  • 当某个客户端断开(下线),需要处理

完整代码

#include<stdio.h>
#include<Windows.h>
#include<process.h>
#pragma comment(lib,"ws2_32.lib")
#define MAX_CLNT 256
#define MAX_BUF_SIZE 1024

SOCKET clnSocks[MAX_CLNT]; //所有连接的SOCKET客户端
int clntCnt = 0; //当前SOCKET连接数

HANDLE hMutex;

void SendMsg(char* szMsg, int iLen)
{
int i = 0;
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < clntCnt; i++)
{
send(clnSocks[i], szMsg, iLen, 0);

}
ReleaseMutex(hMutex);
}
unsigned WINAPI HandleCln(void* arg)
{
SOCKET hClntSock = *((SOCKET*)arg);
int iLen = 0, i;
char szMsg[MAX_BUF_SIZE] = { 0 };
while (1)
{
iLen = recv(hClntSock, szMsg, sizeof(szMsg), 0);
if (iLen != -1)
{
SendMsg(szMsg, iLen);
}
else
break;
}
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < clntCnt; i++)
{
if (hClntSock == clnSocks[i])
{
for (int j = i; j < clntCnt; j++)
{
clnSocks[j] = clnSocks[j + 1];
}
break;
}
}
clntCnt--;
ReleaseMutex(hMutex);
closesocket(hClntSock);
return 0;
}

int main()
{
HANDLE hThread;

WORD wVersionRequested;
WSADATA wsadata;
int err;
wVersionRequested = MAKEWORD(2, 2);

err = WSAStartup(wVersionRequested, &wsadata);
if (err)
{
printf("WSAStartup errnum: %d\n", GetLastError());
return err;
}

if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2)
{
printf("LOBYTE errnum: %d\n", GetLastError());
WSACleanup();
return -1;
}
//创建互斥对象
hMutex = CreateMutex(NULL, FALSE, NULL);

//创建服务器SOCKET
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockSrv)
{
printf("%d", GetLastError());
return -1;
}

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(9999);

if (SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
{
printf("%d", GetLastError());
return -1;
}

if (SOCKET_ERROR == listen(sockSrv, 5))
{
printf("%d", GetLastError());
return -1;
}

printf("start listen");

SOCKADDR_IN addrCli;
int len = sizeof(SOCKADDR_IN);

while (1)
{
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len);
WaitForSingleObject(hMutex, INFINITE);
clnSocks[clntCnt++] = sockConn;
ReleaseMutex(hMutex);
hThread = (HANDLE)_beginthreadex(NULL, 0, &HandleCln, (void*)&sockConn, 0, NULL);
printf("Connect ip = %s\nNum = %d", inet_ntoa(addrCli.sin_addr), clntCnt);


}

closesocket(sockSrv);
return 0;

}