E008

调用orsci-art中的TCP,实现TCP多线程客户/服务器编程演示。

 

#pragma once

#include "ARTTCP.h"

namespace TEST_TCP
{
using namespace art;


class TMyTCPServer : public TTCPServer
{
public:

virtual void OnAccept(const string & ARemoteIP, const int & ARemotePort, bool & retAcceptAllowFlag) override
{
cout << "[Information]TMyServer::OnAccept()" << ARemoteIP << " : " << ARemotePort << endl;
}
virtual void OnConnect(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort, void * & userDefinedPointer) override
{
cout << "[Information]TMyServer::OnConnect()" << ARemoteIP << " : " << ARemotePort << endl;
} //在成功打开时触发。
virtual void OnDisconnect(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort, void * & userDefinedPointer) override
{
cout << "[Information]TMyServer::OnDisconnect()" << ARemoteIP << " : " << ARemotePort << endl;
} //在关闭时候触发。
virtual void OnSendData(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort, const char * ADataBuffer, const int ADataLen, const void * userDefinedPointer) override
{
cout << "[Information]TMyServer::OnSendData()" << ARemoteIP << " : " << ARemotePort << endl;
} //在发送数据时候触发。
virtual void OnRecvData(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort, const char * ADataBuffer, const int ADataLen, const void * userDefinedPointer) override
{
cout << "[Information]TMyServer::OnRecvData()" << ARemoteIP << " : " << ARemotePort << " 数据长度:" << ADataLen << endl;
if (ADataLen == 4) {int * pInt = (int *)(ADataBuffer); cout << *pInt << endl; *pInt += 1;} //这里按照整数解析,至于数据的含义需要客户端和服务器约定!
int mErrorCode = 0;
int mFlag = ASocket.SendBuffer((char *)ADataBuffer, ADataLen, mErrorCode, 0);
//int mFlag = SendBuffer(ARemoteIP, ARemotePort, (char *)ADataBuffer, ADataLen, mErrorCode, 0);
cout << "数据回传数据量:" << mFlag << endl;
} //在接收到数据的时候触发。
virtual void OnException(int AExceptionCode, const string & AExceptionMsg, bool & retIgnoreException) override
{
cout << "[ARTError]出现了错误:" << AExceptionCode << " " << AExceptionMsg << endl;
}

};


class TMyTCPClient : public TTCPClient
{
public:
virtual void OnConnect(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort) override
{
cout << "[Information]TMyClient::OnConnect()" << ARemoteIP << " : " << ARemotePort << endl;
}
virtual void OnDisconnect(_TTCPSocket & ASocket, const string & ARemoteIP, const int & ARemotePort) override
{
cout << "[Information]TMyClient::OnDisconnect()" << ARemoteIP << " : " << ARemotePort << endl;
}
virtual void OnSendData(_TTCPSocket & ASocket, const char * ADataBuffer, const int ADataLen) override
{
cout << "[Information]TMyClient::OnSendData()" << ServerIP() << " : " << ServerPort() << endl;
}
virtual void OnRecvData(_TTCPSocket & ASocket, const char * ADataBuffer, const int ADataLen) override
{
cout << "[Information]TMyClient::OnRecvData()" << ServerIP() << " : " << ServerPort() << endl;
if (ADataLen == 4) {int * pInt = (int *)(ADataBuffer); cout << *pInt << endl;} //这里按照整数解析,至于数据的含义需要客户端和服务器约定!
}
virtual void OnException(int AExceptionCode, const string & AExceptionMsg, bool & retIgnoreException) override
{
cout << "[Information]TMyClient::OnException()" << ServerIP() << " : " << ServerPort() << endl;
}
};


inline void Test_TCPServer() //测试TCP的服务器
{
cout << "===========================================" << endl;
cout << "// TCP Server 2.0 Demo" << endl;
cout << "Website:http://www.orsci.cn; http://www.jiangw.cn" << endl;
cout << "===========================================" << endl;
TMyTCPServer tcpser;
cout << "操作说明:" << endl;
cout << "0--进行统计输出,100--之后退出" << endl;
cout << "9--显示当前客户列表!" << endl;
cout << "5--启动服务; 6--关闭服务!" << endl;
cout << "7--断开指定用户!" << endl;
tcpser.BoundLocal("127.0.0.1", 4612);
while (true)
{
cout << "输入数值:";
int mCommand;
cin >> mCommand;
if (mCommand >= 100) break;
if (mCommand == 5)
{
if (tcpser.is_active())
cout << "服务器已经启动" << endl;
else
tcpser.Open();
}
if (mCommand == 6)
{
if (tcpser.is_active() == false)
cout << "服务器已经关闭!" << endl;
else
tcpser.Close();
}
if (mCommand == 7)
{
unsigned short int mPeerPort = 0;
cout << "请输入要断开用户的端口:";
cin >> mPeerPort;
if (mPeerPort > 0)
{
tcpser.DisconnectClient("127.0.0.1", mPeerPort);
}
}
if (mCommand == 9)
{
tcpser.getClientTable().DispClientInfoTable(0);
}
}

cout << "程序结束!" << endl;
//char xxpp;
//cin >> xxpp;
}


inline void Test_TCPClient()
{
cout << "===========================================" << endl;
cout << "// TCP Client 2.0 Demo" << endl;
cout << "Website:http://www.orsci.cn; http://www.jiangw.cn" << endl;
cout << "===========================================" << endl;
TMyTCPClient tcp;
cout << "操作说明:" << endl;
cout << "0--进行统计输出,100--之后退出" << endl;
cout << "1--发出测试数据!" << endl;
cout << "5--连接到服务器; 6--断开连接!" << endl;
tcp.EnableNagle(false);
tcp.BoundLocal("127.0.0.1", 0);
cout << "本地信息:" << tcp.LocalIP() << " " << tcp.LocalPort() << endl;
while (true)
{
cout << "输入数值:";
int mCommand;
cin >> mCommand;
if (mCommand >= 100) break;
if (mCommand == 5)
{
if (tcp.is_active())
cout << "客户端已经连接到服务器" << endl;
else
tcp.Connect("127.0.0.1", 4612);
}
if (mCommand == 6)
{
if (tcp.is_active() == false)
cout << "远程服务器连接已经关闭!" << endl;
else
tcp.Disconnect();
}
if (mCommand == 1)
{
if (tcp.is_active() == false)
{
cout << "当前还没有连接!" << endl;
}
else
{
BOOL abc = 1;
int mLenLen = sizeof(abc);
getsockopt(tcp.tcpsocket(), IPPROTO_TCP, TCP_NODELAY, (char *)&abc, &mLenLen);
cout << "当前Nagle参数值!" << abc << endl;
int mValue = rand();
cout << "输入一个将发送的整数:";
cin >> mValue;
int mErrorCode = 0;
int mFlag = tcp.SendBuffer((char *)&mValue, sizeof(mValue), mErrorCode, 10000);
cout << "发送标记:" << mFlag << " 数据值:" << mValue << endl;
}
}
}

cout << "程序结束!" << endl;
//char xxpp;
//cin >> xxpp;
}

}; //end namespace


namespace art
{
inline void E008_Demo(const bool flagRunServer)
{
cout << "E008:TCP编程举例....Server...http://www.orsci.cn" << endl;

if (flagRunServer) TEST_TCP::Test_TCPServer();
else TEST_TCP::Test_TCPClient();
}
}; //end namespace art

输出

(一)服务器运行图

.TCP服务器运行图

(二)TCP客户端运行图

TCP客户端运行图

(三)说明:

(1)TCP按照C/S模式编程。服务器和客户端都是多线程运行。服务器启动后等待客户连接;客户端可以启动多个程序,同时连接到服务器。

(2)客户端发一个整数,用作测试,服务器接收该整数,并将整数值加1之后返回给客户端,用于演示存在交互通信过程。

(3)在orsci-art包中,使用TTCPServer和TTCPClient类作为基础类,各派生出子类后分别来创建TCP服务器和TCP客户端。

(4)关于TCP的工作原理和实现原理,请参见配套教材:姜维. 《分布式网络系统与Multi-Agent系统编程框架》

(5)orsci-art包支持TCP网络编程,提供TTCPServer和TTCPClient类,以及多线程编程、多线程协调控制等程序。可下载配套软件orsci进行应用。

书籍 姜维. 《分布式网络系统与Multi-Agent系统编程框架》
软件 orsci-art开发包(C++语言)。