1、先看一下运行成果:
![](https://i-blog.csdnimg.cn/blog_migrate/9747bc110d07bf6e2eba889912a83a8a.png)
服务器已经在之前启动,并且服务器被隐藏在后台,所以并不会显示出来。
客户端之间聊天方式为:[客户端ID:聊天信息],例如:828:你是谁.
客户端与服务器之间:直接输入数字1-3
2、服务器代码分析
服务器头文件
class TCPServer
{
public:
/* @接口 默认构造函数
* @邮箱 575814050@qq.com
*/
TCPServer();
/* @接口 默认析构函数
* @邮箱 575814050@qq.com
*/
~TCPServer();
/* @接口 创建客户端ID
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
long createClientGuid();
/* @接口 初始化服务器
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
virtual bool initServer();
/* @接口 开始等待连接
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
virtual bool beginAccept(int count = 64);
/* @接口 创建服务器,int为端口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
virtual bool createServer(int, const QString &ip = "127.0.0.1");
public:
/* @接口 服务器套接字
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
SOCKET sock();
/* @接口 接受信息
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
QString recv(const SOCKET &);
/* @接口 响应客户端
* @参数 int 客户端标识ID,QString 客户端发过来的信息
* @邮箱 575814050@qq.com
*/
void respondClient(int, const QString &);
/* @接口 发送信息到指定的客户
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
*/
bool send(const SOCKET &, const QString &);
/* @接口 服务器线程
* @邮箱 575814050@qq.com
*/
static DWORD serverThread(LPVOID);
public:
int m_listen;
int m_current;
SOCKET _socket;
QList<SOCKET> m_socks;
};
服务器源文件
#include "server.h"
TCPServer::TCPServer()
: m_listen(0)
, m_current(0)
{
}
TCPServer::~TCPServer()
{
closesocket(_socket);
WSACleanup();
}
SOCKET TCPServer::sock()
{
return _socket;
}
QString TCPServer::recv(const SOCKET &_sock)
{
int size = 4096; char buf[4096] = {0};
int ret = ::recv(_sock, buf, size, 0);
if(ret == -1) return "Exit";
QString recvinfo = QString::fromLocal8Bit(buf, ret - 1);
return recvinfo;
}
bool TCPServer::initServer()
{
WSADATA wsa;
int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
return ret != -1;
}
//接口作废
long TCPServer::createClientGuid()
{
long val = rand() % 65536;
// if(!g_client.contains(val)) return val;
// for(;;)
// {
// val = rand() % 65536;
// if(!g_client.contains(val)) break;
// }
return val;
}
bool TCPServer::beginAccept(int len)
{
m_listen = len;
listen(_socket, len);
int size = sizeof(SOCKADDR);
char buf[1024] = {0};
sockaddr_in *addr_v4;
while((len--) > 0)
{
SOCKADDR addr; SOCKET _sock;
_sock = accept(_socket, (SOCKADDR *)&addr, &size);
if(0 == getpeername(_sock, &addr, &size))
{
if(addr.sa_family == AF_INET)
addr_v4 = (sockaddr_in*)&addr;
}
m_socks.append(_sock); this->send(_sock, QS("%1").arg(_sock));
HANDLE handle = CreateThread(NULL, 0, serverThread, this, 0, NULL);
CloseHandle(handle); m_current++;
}
return true;
}
void TCPServer::respondClient(int cur, const QString &cmd)
{
int idx = 0; QString info;
switch(cmd.toInt())
{
case 1:
info = QS("client total:<%1> count.").arg(m_socks.length());
break;
case 2:
info = QS("server listen <%1>, but connected <%2>, the server at best connecting <%3>").arg(m_listen).arg(m_current).arg(m_listen - m_current);
break;
case 3:
for(idx = 0; idx < m_current - 1; ++idx)
info += QS("client [%1] be connected.\n").arg(m_socks[idx]);
info += QS("client [%1] be connected.").arg(m_socks.last());
break;
}
if(info.length() != 0)
this->send(m_socks[cur], info);
}
DWORD TCPServer::serverThread(LPVOID param)
{
if(param == NULL) return -1;
TCPServer *server = (TCPServer *)param;
char Buffer[1024] = {0}; int cur = server->m_current - 1;
while(true)
{
QString buf = server->recv(server->m_socks[cur]);
if(buf.compare("pipe", Qt::CaseInsensitive) == 0)
{
dox::Object<dox::IPipeServer> pipe(NIL);
pipe->initPipe(dox::IPipeServer::DoublePipe);
dox::IPipeServer::PipeSyntony _syntony;
pipe->pickChild(); pipe->setOutputType(&_syntony);
pipe->createPipe(); pipe->createChild();
while(true)
{
buf = server->recv(server->m_socks[cur]);
if(buf.compare("exit", Qt::CaseInsensitive) == 0) break;
pipe->writePipeData(buf);
QString info = pipe->readPipeData();
server->send(server->m_socks[cur], info);
}
}
if(buf.compare("exit", Qt::CaseInsensitive) == 0)
{
closesocket(server->m_socks[cur]);
server->m_socks.removeAt(cur);
return -1;
}
if(buf == "Clear")
{
for(int idx = 0; idx < server->m_socks.length(); ++idx)
closesocket(server->m_socks[idx]);
return -1;
}
int pos = buf.indexOf(":");
if(pos == -1)
server->respondClient(cur, buf);
else
{
long des_guid = buf.left(pos).toLong();
buf = QS("%1%2").arg(server->m_socks[cur]).arg(buf.mid(pos));
server->send(des_guid, buf);
}
}
return 0;
}
bool TCPServer::createServer(int port, const QString &ip)
{
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(_socket == INVALID_SOCKET) return false;
sockaddr_in addrServ;
memset(&addrServ, 0, sizeof(sockaddr_in));
QString IP = ip.length() == 0 ? "127.0.0.1" : ip;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(port);
addrServ.sin_addr.s_addr = INADDR_ANY; //inet_addr(IP.toLocal8Bit().constData());
int ret = bind(_socket, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
return true;
}
bool TCPServer::send(const SOCKET &_sock, const QString &info)
{
char sendinfo[4096] = {0};
sprintf(sendinfo, "%s", info.toLocal8Bit().constData());
::send(_sock, sendinfo, info.length() + 1, NULL);
return true;
}
//源文件结束
客户端代码将在下一篇文章中介绍。https://mp.csdn.net/postedit/84028009
示例程序下载地址:https://download.csdn.net/download/yangfahe1/10781733
示例程序运行方式:https://blog.csdn.net/yangfahe1/article/details/84028318