/**
* Windows(VC6)下C语言并发服务器 线程池 聊天服务器
* 设置:工程——设置——C/C++——分类:Code Generation, User run-time library:Multithreader
* 作者:PangJianhong
* 时间:2015-1-11
*/
#pragma comment(lib, "ws2_32.lib")
#include <Winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h> // for _beginthread()
#define PORT 20000
#define BUFF 1024
int count1 = 0;
int count = 0;
char rbuf[BUFF];
struct Users{
char uname[30];
SOCKET uAddr; //存储用户已连接套接字
};
Users user_s[63];
struct R_Q //服务器接收客户端的数据
{
int siqun; //私聊还是群发
char srcName[30]; //发送消息的用户
char tagName[30]; //私聊时要发送的用户
char data[BUFF]; //发送的数据
};
void WorkerThread(void *param);
int main()
{
WSADATA wsaData;
WORD sv = MAKEWORD(2, 2);
if(WSAStartup(sv, &wsaData) != 0)
{
return -1;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if(SOCKET_ERROR == sock)
{
printf("socket() Failed():%d\n", WSAGetLastError());
return -1;
}
sockaddr_in sAddr;
sAddr.sin_family = AF_INET;
sAddr.sin_port = htons(PORT);
sAddr.sin_addr.S_un.S_addr = INADDR_ANY;
if(SOCKET_ERROR == bind(sock, (LPSOCKADDR)&sAddr, sizeof(sAddr)))
{
printf("bind() Failed:%d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
}
if(SOCKET_ERROR == listen(sock, 5))
{
printf("listen() Failed:%d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
}
for (int i = 0; i < 63; i++)
{
_beginthread(WorkerThread, 0, (void *)sock);
}
Sleep(INFINITE);
closesocket(sock);
WSACleanup();
return 0;
}
void WorkerThread(void *param)
{
printf("Thread:%d\n", ++count1);
SOCKET sockListen = (SOCKET)param;
sockaddr_in cAddr;
int cLen = sizeof(cAddr);
while(1)
{
//监听
SOCKET sockConn = accept(sockListen, (sockaddr *)&cAddr, &cLen);
memset(rbuf, 0, BUFF);
if(recv(sockConn, rbuf, BUFF, 0) < 0) //首次接收数据为用户登录
{
printf("recv() Failed:%d\n", WSAGetLastError());
closesocket(sockConn);
continue;
}
printf("用户名:%s 地址:%s 上线\n", rbuf, inet_ntoa(cAddr.sin_addr));
if(send(sockConn, rbuf, BUFF, 0) < 0)
{
printf("send() Failed!\n");
closesocket(sockConn);
continue;
}
strcpy(user_s[count].uname, rbuf); //保存用户名
user_s[count].uAddr = sockConn; //保存地址
count++;
R_Q r_q, *rq;
while(1)
{
memset(rbuf, 0, BUFF);
if(recv(sockConn, rbuf, BUFF, 0) < 0) //其次接收数据为 私聊/群发和要发送的数据
{
printf("recv() Failed!\n");
break;
}
rq = (R_Q *)rbuf;
memcpy(&r_q, rbuf, sizeof(R_Q));
printf("私聊/群发:%d 发送的用户:%s 接收的用户:%s 数据:%s\n", r_q.siqun, r_q.srcName, r_q.tagName, r_q.data);
if(1 == r_q.siqun)
{
for(int h = 0; h < count; h++) //查找已登录的用户
{
if(0 == strcmp(user_s[h].uname, r_q.tagName))
{
if(send(user_s[h].uAddr, (char *)&r_q, sizeof(r_q), 0) < 0) //转发数据
{
printf("send() Failed!\n");
break;
}
printf("%s-%s:%s\n", r_q.srcName, r_q.tagName, r_q.data);
break;
}
}
}
else if(2 == r_q.siqun)
{
for (int p = 0; p < count; p++) //发送给所有已连接的客户端
{
if(send(user_s[p].uAddr, (char *)&r_q, sizeof(r_q), 0) < 0)
{
printf("send() Failed!\n");
break;
}
}
}
else
{
printf("Error!!\n");
}
}
// 客户端断开后对客户端的序号进行排序
for(int m = 0; m < count; m++)
{
if(user_s[m].uAddr == sockConn)
{
int us = m;
for(us; us < count; us++)
{
user_s[us] = user_s[us+1];
}
break;
}
}
closesocket(sockConn);
count--; //套接字断开后已连接客户-1
}
}