本人新手,写一篇文章纪念一下-.-
喜不喜欢都可以说,喷我就请联系我再喷呗,如果在评论下面喷多不好-。-
这一个是使用服务器作为消息转发的中介,使用了队列,废话不多说直接上代码:
以下是服务器端代码:
//TcpServer.cpp
#include <stdio.h>
#include<queue>
#include <winsock2.h>
#include<string.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
DWORD WINAPI ListenThread(LPVOID);//接收每一个信息到队列中
DWORD WINAPI SendThread();//发送消息队列中的每一个消息
DWORD WINAPI oneThread(LPVOID lpParameter);//总线程
DWORD WINAPI acceptThread(LPVOID lpParameter);//监听是否有新的客户端
DWORD WINAPI recvThread();//监听每个客户端
typedef struct sclient {
SOCKET socket;
char name[10];//客户端名称
char aim[10];//客户端目标
int flag;//是否创建监听线程
}sclient;
typedef struct Message {
char news[128];//消息
char aim[10];//目的用户
char name[10];//
}Message;
sclient Asclient[10];//客户端结构体
queue <Message> message;//消息队列
int flag = 0;//多少客户端
char flag2[10];
int t = 0;
int change = 0;//是否有新的客户端连接进来
SOCKET getsocket(char tem[]) {
int i;
for (i = 0; i < flag; i++) {
if (strcmp(tem, Asclient[i].name)==0) {
memset(flag2, 0, sizeof(flag2));
strcpy(flag2, Asclient[i].name);
return Asclient[i].socket;
}
}
printf("no named client---------------\n");
return 0;
}
int main()
{
//初始化套接字接口
WSADATA wsaData;
WSAStartup(0x202, &wsaData);
int i;
//创建套接字s
SOCKET s;
s = socket(AF_INET, SOCK_STREAM, 0);
//打印套接字s在创建时的信息
//定义地址结构
struct sockaddr_in serveraddr;
memset((void *)&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);// INADDR_ANY 转换过来就是0.0.0.0,表示本机的所有IP
//serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serveraddr.sin_port = htons(5000);
//绑定套接字
i=bind(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (i >= 0) {
printf("绑定端口成功,正在开始服务器线程..........\n");
HANDLE hListen = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)oneThread,
(LPVOID)&s, 0, NULL);
}
else {
printf("服务器初始化失败.........................\n");
}
for (i = 0; i < 1000; i++)
Sleep(100000);
//关闭套接字s
closesocket(s);
WSACleanup();
//程序中断
system("pause");
return 0;
}
DWORD WINAPI oneThread(LPVOID lpParameter) {
SOCKET s;
s = *((SOCKET *)lpParameter);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)acceptThread,
(LPVOID)&s, 0, NULL);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendThread,
NULL, 0, NULL);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)recvThread,
NULL, 0, NULL);
return 0;
}
DWORD WINAPI recvThread() {
int i;
SOCKET tems;
while (1) {
if (change == 1&&flag>1) {
for (i = 0; i < flag; i++) {
if (Asclient[i].flag != 1) {
printf("开始接受信息..........3\n");
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ListenThread,
(LPVOID)&Asclient[i], 0, NULL);
Asclient[i].flag = 1;
}
}
change = 0;
}
}
return 0;
}
DWORD WINAPI acceptThread(LPVOID lpParameter) {
int i = 0;
int ret;
SOCKET ss;
SOCKET s;
SOCKET ts;
SOCKADDR_IN g_ClientAddr = { 0 };
char buf[10];
char IP[20];
s = *((SOCKET *)lpParameter);
while (1) {
listen(s, SOMAXCONN);
if (flag<10) {
printf("正在监听端口\n");
if ((ss = accept(s, NULL, NULL)) == INVALID_SOCKET) {
continue;
}
else
{
printf("有客户端请求\n");
memset(buf, 0, sizeof(buf));
Asclient[i].socket = ss;
ret = recv(ss, buf, sizeof(buf), 0);
if (ret > 0) {
strcpy(Asclient[i].name, buf);
}
memset(buf, 0, sizeof(buf));
ret = recv(ss, buf, sizeof(buf), 0);
if (ret > 0) {
strcpy(Asclient[i].aim, buf);
}
printf("新客户端连接成功,用户名:%s 聊天目标: %s\n", Asclient[i].name, Asclient[i].aim);
i++;
flag++;
change = 1;
}
}
else {
printf("当前客户端已满,请稍等再访问................\n");
return 0;
}
}
return 0;
}
DWORD WINAPI ListenThread(LPVOID lpParameter) {
sclient s;
Message temmessage;
char buf[128];
int ret;
s = *((sclient *)lpParameter);
strcpy(temmessage.aim, s.aim);
strcpy(temmessage.name, s.name);
while (1) {
memset(buf, 0, sizeof(buf));
ret = recv(s.socket, buf, sizeof(buf), 0);
if (ret > 0) {
strcpy(temmessage.news, buf);
message.push(temmessage);
}
else
{
t++;
printf("%d", t);
t--;
Sleep(1000);
}
}
}
DWORD WINAPI SendThread() {
SOCKET s;
Message temmessage;
char tem;
while (1) {
if (message.empty()==FALSE){
temmessage = message.front();
s = getsocket(temmessage.aim);
send(s,temmessage.name, sizeof(temmessage.name), 0);
send(s, temmessage.news, sizeof(temmessage.news), 0);
message.pop();
}
}
return 0;
}
服务器端的代码使用一个线程来监听是否有新的客户端连接,使用一个线程来接受客户端的信息,使用一个线程来转发服务器接收到的信息,看代码就很好懂了。一下是客户端代码:
//TcpClient.cpp
#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib,"ws2_32.lib")
DWORD WINAPI ListenThread(LPVOID);
DWORD WINAPI SendThread(LPVOID);
char tem1[10];
int main()
{
//初始化套接字接口
WSADATA wsaData;
WSAStartup(0x202, &wsaData);
int i;
//创建套接字s
SOCKET s;
s = socket(AF_INET, SOCK_STREAM, 0);
//printf("%d\n",sizeof(s));
//指定服务器的地址结构
struct sockaddr_in serveraddr;
memset((void *)&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serveraddr.sin_port = htons(5000);
//发送连接请求给服务器
i=connect(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (i >= 0) {
memset(tem1, 0, sizeof(tem1));
printf("成功与服务端连接:现在开始通话----------------\n");
printf("请输入你的用户名: ");
scanf("%s", tem1);
send(s, tem1,sizeof(tem1), 0);
memset(tem1, 0, sizeof(tem1));
printf("请输入你要聊天的人的用户名: ");
scanf("%s", tem1);
send(s, tem1, sizeof(tem1), 0);
HANDLE hListen = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ListenThread,
(LPVOID)&s, 0, NULL);
HANDLE hListen1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendThread,
(LPVOID)&s, 0, NULL);
}
else {
printf("连接失败\n");
}
//关闭套接字s
for (i = 0; i < 1000; i++)
Sleep(100000);
closesocket(s);
//注销套接字接口
WSACleanup();
//程序中断
system("pause");
return 0;
}
DWORD WINAPI ListenThread(LPVOID lpParameter) {
SOCKET s;
char buf[128] = { 0 };
int ret;
s = *((SOCKET *)lpParameter);
while (1) {
memset(buf, 0, sizeof(buf));
ret = recv(s, buf, sizeof(buf), 0);
if (ret > 0) {
printf("%s 说: ",buf);
}
memset(buf, 0, sizeof(buf));
ret = recv(s, buf, sizeof(buf), 0);
if (ret > 0) {
printf("%s\n", buf);
}
}
}
DWORD WINAPI SendThread(LPVOID lpParameter) {
SOCKET s;
char buf[128];
char buf1[129];
char tem;
s = *((SOCKET *)lpParameter);
while (1) {
memset(buf, 0, sizeof(buf));
scanf("%s", &buf);
send(s, buf, sizeof(buf), 0);
}
}
客户端相比之下就比较简单了,直接使用两个线程分别来接受消息以及发送消息。
有什么不足的地方请指教一下,有一个问题就是CPU的使用率会有一点高,目前可以支持10个客户端之间相互通信,你也可以自己修改相应的参数就可以了。