C++ネットワークプログラミング学習:ソースコードのパッケージ
ネットワークプログラミング学習レコード使用言語はC/C+ ソースコードサポートプラットフォームは、Windows/Linux 笔记一:基础TCP服务端/クライアント 点我跳转笔记二:ネットワークデータメッセージの送受信 点我跳转笔记三:selectネットワークモデル 点我跳转笔记四:プラットフォームをまたいでWindowsをサポート、Linuxシステム 点我跳转笔记5:ソースコードのパッケージ 点我跳转笔记6:バッファオーバーフローと粘着包分包 点我跳转笔记7:サービス端マルチスレッド分离业务処理高负荷 点我跳转笔记
ノート5ネットワークプログラミング学習記録 一、なぜパッケージ操作を行うのか 二、パッケージの考え方と関連 1.パッケージヘッダファイル選択 2.クライアントクラスのパッケージ 3.サービス側クラスのパッケージ 三、パッケージ後の詳細なソースコードとその注釈 1.クライアント TcpClient.hpp client_test.cpp
2.サービス側 TcpServer.hpp server_test.cpp
一、なぜパッケージ操作を行うのか
オブジェクト向けプログラミング言語として,オブジェクト向けの考え方でソースコードの作成を行う. 主なソースコードをカプセル化した後、クライアントとサービス側のコードの作成がより明確になり、論理性がより強く、開発とメンテナンスが容易になった.また,今後のサービス側高同時テストでは,複数の接続を新規作成してテストするのが容易である. 本ノートでは、ノート4のソースコードに基づいてパッケージ化し、クライアントとサービス側のソースコードをパッケージ化する際の考え方と手順を記録します.最終ソースコードはクライアントパッケージクラスファイルTcpClientである.hppとサービス側はクラスファイルTcpServerをカプセル化する.hpp、およびクライアントソースclient_test.cppとサービス側ソースサーバ_test.cpp.
二、パッケージの考え方と関連
1.カプセル化されたヘッダファイルの選択
カプセル化クラスは、まずヘッダファイルにカプセル化性を体現しなければならない.今回のパッケージでは、より便利に保存できるようにhppヘッダファイルを選びました.すなわち、クラス宣言とクラス定義はこのファイルにあります.
2.クライアントクラスのカプセル化
まず、クライアントの大まかな流れは以下の通りです.
したがって、パッケージ化する方法は次のとおりです.
この考え方に従って、クライアントのソースコードの考え方は:
OnRun()メソッドではselectネットワーク構造を使用しており、selectが処理対象イベントをフィルタリングした後、RecvData()メソッドを使用してパケットとパケットの受信を行い、その後NetMsg()メソッドを呼び出し、パケットヘッダのメッセージタイプに応じてパケットデータを処理する.NetMsg()メソッドはダミーメソッドであり,後でこのパッケージクラスを呼び出すと継承リロード操作を行うことができ,データ応答の操作を変更しやすい.関連ソースコードは以下の通りである:
また、カプセル化されているため、メソッドを呼び出す際にステップエラーが発生する可能性があります.たとえば、新しいソケットを作成しないでconnect接続を行うか、ソケットを閉じるか、データの転送にエラーがあるなど、問題が発生します.私がこのような問題を解決する方法は、多くの判定を加えることです.例えば、ソケットが確立されているか、あるいは入力データに誤りがあるかなどを判定し、その後、状況に応じて処理する.詳細は下記をご覧ください.
3.サービス側クラスのパッケージ
まず、クライアントの大まかな流れは以下の通りです.
したがって、パッケージ化する方法は次のとおりです.
この考え方に従って、クライアントのソースコードの考え方は:
OnRun()メソッドではselectネットワーク構造が使用されます.selectが処理対象イベントをフィルタリングした後、新しい接続の場合、Accept()メソッドを使用して新しいクライアント接続操作を行います.クライアントに接続されている受信対象イベントの場合は、RecvData()メソッドを使用してパケットヘッダとパケットの受信を行い、その後NetMsg()メソッドを呼び出し、パケットヘッダのメッセージタイプに応じてパケットデータを処理します.NetMsg()メソッドはダミーメソッドであり,後でこのパッケージクラスを呼び出すと継承リロード操作を行うことができ,データ応答の操作を変更しやすい.関連ソースコードは以下の通りである:
また、カプセル化されているため、メソッドを呼び出す際にステップエラーが発生する可能性があります.たとえば、新しいソケットを作成しないままbindバインドポートIPを実行したり、ソケットをオフにしたり、データの転送に誤りがあったりすると、問題が発生します.私がこのような問題を解決する方法は、多くの判定を加えることです.例えば、ソケットが確立されているか、あるいは入力データに誤りがあるかなどを判定し、その後、状況に応じて処理する.詳細は下記をご覧ください.
三、パッケージ後の詳細なソースコードとその注釈
1.クライアント
TcpClient.hpp
client_test.cpp
2.サービス側
TcpServer.hpp
server_test.cpp
ノート5
一、なぜパッケージ操作を行うのか
オブジェクト向けプログラミング言語として,オブジェクト向けの考え方でソースコードの作成を行う. 主なソースコードをカプセル化した後、クライアントとサービス側のコードの作成がより明確になり、論理性がより強く、開発とメンテナンスが容易になった.また,今後のサービス側高同時テストでは,複数の接続を新規作成してテストするのが容易である. 本ノートでは、ノート4のソースコードに基づいてパッケージ化し、クライアントとサービス側のソースコードをパッケージ化する際の考え方と手順を記録します.最終ソースコードはクライアントパッケージクラスファイルTcpClientである.hppとサービス側はクラスファイルTcpServerをカプセル化する.hpp、およびクライアントソースclient_test.cppとサービス側ソースサーバ_test.cpp.
二、パッケージの考え方と関連
1.カプセル化されたヘッダファイルの選択
カプセル化クラスは、まずヘッダファイルにカプセル化性を体現しなければならない.今回のパッケージでは、より便利に保存できるようにhppヘッダファイルを選びました.すなわち、クラス宣言とクラス定義はこのファイルにあります.
2.クライアントクラスのカプセル化
まず、クライアントの大まかな流れは以下の通りです.
1. socket
2.
3.
while(true)
{
4. select
5. , ( / )
}
6. socket
:
while(1)
{
1.
2.
}
したがって、パッケージ化する方法は次のとおりです.
// socket
int InitSocket();
//
int Connect(const char *ip,unsigned short port);
// socket
void CloseSocket();
//
bool OnRun();
//
bool IsRun();
//
int SendData(DataHeader *_head);
//
int RecvData(SOCKET _temp_socket);
//
virtual void NetMsg(DataHeader *_head);
この考え方に従って、クライアントのソースコードの考え方は:
1.InitSocket();// socket
2.Connect(const char *ip,unsigned short port);// IP
3.
while(4.IsRun())//
{
5.OnRun();//
}
6.CloseSocket();// socket
:
while(1.IsRun())//
{
2.
3.SendData(DataHeader *_head);
}
OnRun()メソッドではselectネットワーク構造を使用しており、selectが処理対象イベントをフィルタリングした後、RecvData()メソッドを使用してパケットとパケットの受信を行い、その後NetMsg()メソッドを呼び出し、パケットヘッダのメッセージタイプに応じてパケットデータを処理する.NetMsg()メソッドはダミーメソッドであり,後でこのパッケージクラスを呼び出すと継承リロード操作を行うことができ,データ応答の操作を変更しやすい.
//
bool OnRun()
{
if(IsRun())//
{
fd_set _fdRead;//
FD_ZERO(&_fdRead);//
FD_SET(_sock,&_fdRead);//
timeval _t = {
1,0};//select
// seclect
int _ret = select(_sock+1,&_fdRead,NULL,NULL,&_t);
if(_ret<0)
{
printf("seclect
");
return false;
}
if(FD_ISSET(_sock,&_fdRead))// socket
{
FD_CLR(_sock,&_fdRead);//
if(-1 == RecvData(_sock))
{
CloseSocket();
return false;
}
}
return true;
}
return false;
}
//
int RecvData(SOCKET _temp_socket)//
{
//
char buffer[4096] = {
};
//
int _buf_len = recv(_temp_socket,buffer,sizeof(DataHeader),0);
DataHeader *_head = (DataHeader*)buffer;
if(_buf_len<=0)
{
printf(" ,
");
return -1;
}
recv(_temp_socket,buffer+sizeof(DataHeader),_head->date_length-sizeof(DataHeader),0);
//
NetMsg(_head);
return 0;
}
//
virtual void NetMsg(DataHeader *_head)
{
printf(" , :%d, :%d
",_head->cmd,_head->date_length);
switch(_head->cmd)
{
case CMD_LOGINRESULT://
{
LoginResult *_result = (LoginResult*)_head;
printf(" :%d
",_result->Result);
}
break;
case CMD_LOGOUTRESULT://
{
LogoutResult *_result = (LogoutResult*)_head;
printf(" :%d
",_result->Result);
}
break;
case CMD_NEW_USER_JOIN://
{
NewUserJoin *_result = (NewUserJoin*)_head;
printf(" :%s
",_result->UserName);
}
}
}
また、カプセル化されているため、メソッドを呼び出す際にステップエラーが発生する可能性があります.たとえば、新しいソケットを作成しないでconnect接続を行うか、ソケットを閉じるか、データの転送にエラーがあるなど、問題が発生します.私がこのような問題を解決する方法は、多くの判定を加えることです.例えば、ソケットが確立されているか、あるいは入力データに誤りがあるかなどを判定し、その後、状況に応じて処理する.詳細は下記をご覧ください.
3.サービス側クラスのパッケージ
まず、クライアントの大まかな流れは以下の通りです.
1. socket
2. IP
3.
while(true)
{
4. select socket
5.
6. , ( )
}
7. socket
したがって、パッケージ化する方法は次のとおりです.
// socket
int InitSocket();
// IP/
int Bind(const char* ip,unsigned short port);
//
int Listen(int n);
//
int Accept();
// socket
void CloseSocket();
//
bool OnRun();
//
bool IsRun();
//
int SendData(DataHeader *_head,SOCKET _temp_socket);
//
int RecvData(SOCKET _temp_socket);
//
void NetMsg(DataHeader *_head,SOCKET _temp_socket);
この考え方に従って、クライアントのソースコードの考え方は:
1.InitSocket();// socket
2.Bind(const char* ip,unsigned short port);// IP
3.Listen(int n);//
while(4.IsRun())//
{
5.OnRun();//
}
6.CloseSocket();// socket
OnRun()メソッドではselectネットワーク構造が使用されます.selectが処理対象イベントをフィルタリングした後、新しい接続の場合、Accept()メソッドを使用して新しいクライアント接続操作を行います.クライアントに接続されている受信対象イベントの場合は、RecvData()メソッドを使用してパケットヘッダとパケットの受信を行い、その後NetMsg()メソッドを呼び出し、パケットヘッダのメッセージタイプに応じてパケットデータを処理します.NetMsg()メソッドはダミーメソッドであり,後でこのパッケージクラスを呼び出すと継承リロード操作を行うことができ,データ応答の操作を変更しやすい.
//
bool OnRun()
{
if(IsRun())
{
fd_set _fdRead;//
fd_set _fdWrite;
fd_set _fdExcept;
FD_ZERO(&_fdRead);//
FD_ZERO(&_fdWrite);
FD_ZERO(&_fdExcept);
FD_SET(_sock,&_fdRead);//
FD_SET(_sock,&_fdWrite);
FD_SET(_sock,&_fdExcept);
timeval _t = {
2,0};//select
SOCKET _maxSock = _sock;// socket
// read
for(int n=_clients.size()-1; n>=0; --n)
{
FD_SET(_clients[n],&_fdRead);
if(_maxSock < _clients[n])
{
_maxSock = _clients[n];
}
}
//select select
int _ret = select(_maxSock+1,&_fdRead,&_fdWrite,&_fdExcept,&_t);
if(_ret<0)
{
printf("select
");
CloseSocket();
return false;
}
if(FD_ISSET(_sock,&_fdRead))// socket
{
FD_CLR(_sock,&_fdRead);//
Accept();//
}
// socket
for(int n=0; n<_clients.size(); ++n)
{
if(FD_ISSET(_clients[n],&_fdRead))
{
if(-1 == RecvData(_clients[n]))//
{
std::vector<SOCKET>::iterator iter = _clients.begin()+n;//
if(iter != _clients.end())//
{
_clients.erase(iter);//
}
}
}
}
//printf("
");
return true;
}
return false;
}
//
int RecvData(SOCKET _temp_socket)//
{
//
char buffer[4096] = {
};
//
int _buf_len = recv(_temp_socket,buffer,sizeof(DataHeader),0);
DataHeader *_head = (DataHeader*)buffer;
if(_buf_len<=0)
{
printf("
");
return -1;
}
recv(_temp_socket,buffer+sizeof(DataHeader),_head->date_length-sizeof(DataHeader),0);
//
NetMsg(_head,_temp_socket);
return 0;
}
//
void NetMsg(DataHeader *_head,SOCKET _temp_socket)
{
printf(" , :%d, :%d
",_head->cmd,_head->date_length);
switch(_head->cmd)
{
case CMD_LOGIN://
{
Login *_login = (Login*)_head;
/*
*/
printf("%s
:%s
",_login->UserName,_login->PassWord);
LoginResult *_result = new LoginResult;
_result->Result = 1;
SendData(_result,_temp_socket);
}
break;
case CMD_LOGOUT://
{
Logout *_logout = (Logout*)_head;
/*
*/
printf("%s
",_logout->UserName);
LogoutResult *_result = new LogoutResult();
_result->Result = 1;
SendData(_result,_temp_socket);
}
break;
default://
{
_head->cmd = CMD_ERROR;
_head->date_length = 0;
SendData(_head,_temp_socket);
}
break;
}
}
また、カプセル化されているため、メソッドを呼び出す際にステップエラーが発生する可能性があります.たとえば、新しいソケットを作成しないままbindバインドポートIPを実行したり、ソケットをオフにしたり、データの転送に誤りがあったりすると、問題が発生します.私がこのような問題を解決する方法は、多くの判定を加えることです.例えば、ソケットが確立されているか、あるいは入力データに誤りがあるかなどを判定し、その後、状況に応じて処理する.詳細は下記をご覧ください.
三、パッケージ後の詳細なソースコードとその注釈
1.クライアント
TcpClient.hpp
#ifndef _TcpClient_hpp_
#define _TcpClient_hpp_
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
#include
#pragma comment(lib,"ws2_32.lib")
#else
#include
#include
#include
#define SOCKET int
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif
//
enum cmd
{
CMD_LOGIN,//
CMD_LOGINRESULT,//
CMD_LOGOUT,//
CMD_LOGOUTRESULT,//
CMD_NEW_USER_JOIN,//
CMD_ERROR//
};
//
struct DataHeader
{
short cmd;//
short date_length;//
};
// 1
struct Login : public DataHeader
{
Login()//
{
this->cmd = CMD_LOGIN;
this->date_length = sizeof(Login);
}
char UserName[32];//
char PassWord[32];//
};
// 2
struct LoginResult : public DataHeader
{
LoginResult()//
{
this->cmd = CMD_LOGINRESULT;
this->date_length = sizeof(LoginResult);
}
int Result;
};
// 3
struct Logout : public DataHeader
{
Logout()//
{
this->cmd = CMD_LOGOUT;
this->date_length = sizeof(Logout);
}
char UserName[32];//
};
// 4
struct LogoutResult : public DataHeader
{
LogoutResult()//
{
this->cmd = CMD_LOGOUTRESULT;
this->date_length = sizeof(LogoutResult);
}
int Result;
};
// 5
struct NewUserJoin : public DataHeader
{
NewUserJoin()//
{
this->cmd = CMD_NEW_USER_JOIN;
this->date_length = sizeof(NewUserJoin);
}
char UserName[32];//
};
#include
class TcpClient
{
public:
//
TcpClient()
{
_sock = INVALID_SOCKET;
}
//
virtual ~TcpClient()
{
// socket
CloseSocket();
}
// socket 1
int InitSocket()
{
#ifdef _WIN32
// windows socket 2,x
WORD ver = MAKEWORD(2,2);
WSADATA dat;
if(0 != WSAStartup(ver,&dat))
{
return -1;//-1
}
#endif
// socket
if(INVALID_SOCKET != _sock)
{
printf("
" ,_sock);
CloseSocket();//
}
_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == _sock)
{
return 0;//0 socket
}
return 1;
}
// 1
int Connect(const char *ip,unsigned short port)
{
//
if(INVALID_SOCKET == _sock)
{
InitSocket();
}
//
sockaddr_in _sin = {
};
_sin.sin_family = AF_INET;//IPV4
_sin.sin_port = htons(port);//
#ifdef _WIN32
_sin.sin_addr.S_un.S_addr = inet_addr(ip);//IP
#else
_sin.sin_addr.s_addr = inet_addr(ip);//IP
#endif
if(SOCKET_ERROR == connect(_sock,(sockaddr*)&_sin,sizeof(sockaddr_in)))
{
return 0;//
}
else
{
return 1;//
}
}
// socket
void CloseSocket()
{
if(INVALID_SOCKET != _sock)
{
#ifdef _WIN32
// socket
closesocket(_sock);
// windows socket
WSACleanup();
#else
// socket/LINUX
close(_sock);
#endif
_sock = INVALID_SOCKET;
}
}
//
bool OnRun()
{
if(IsRun())//
{
fd_set _fdRead;//
FD_ZERO(&_fdRead);//
FD_SET(_sock,&_fdRead);//
timeval _t = {
1,0};//select
// seclect
int _ret = select(_sock+1,&_fdRead,NULL,NULL,&_t);
if(_ret<0)
{
printf("seclect
");
return false;
}
if(FD_ISSET(_sock,&_fdRead))// socket
{
FD_CLR(_sock,&_fdRead);//
if(-1 == RecvData(_sock))
{
CloseSocket();
return false;
}
}
return true;
}
return false;
}
//
bool IsRun()
{
return _sock != INVALID_SOCKET;
}
//
int SendData(DataHeader *_head)
{
if(IsRun() && _head)
{
send(_sock,(const char*)_head,_head->date_length,0);
return 1;
}
return 0;
}
//
int RecvData(SOCKET _temp_socket)//
{
//
char buffer[4096] = {
};
//
int _buf_len = recv(_temp_socket,buffer,sizeof(DataHeader),0);
DataHeader *_head = (DataHeader*)buffer;
if(_buf_len<=0)
{
printf(" ,
");
return -1;
}
recv(_temp_socket,buffer+sizeof(DataHeader),_head->date_length-sizeof(DataHeader),0);
//
NetMsg(_head);
return 0;
}
//
virtual void NetMsg(DataHeader *_head)
{
printf(" , :%d, :%d
",_head->cmd,_head->date_length);
switch(_head->cmd)
{
case CMD_LOGINRESULT://
{
LoginResult *_result = (LoginResult*)_head;
printf(" :%d
",_result->Result);
}
break;
case CMD_LOGOUTRESULT://
{
LogoutResult *_result = (LogoutResult*)_head;
printf(" :%d
",_result->Result);
}
break;
case CMD_NEW_USER_JOIN://
{
NewUserJoin *_result = (NewUserJoin*)_head;
printf(" :%s
",_result->UserName);
}
}
}
private:
SOCKET _sock;
};
#endif
client_test.cpp
#include"TcpClient.hpp"
#include
void _cmdThread(TcpClient* tcp)//
{
while(tcp->IsRun())
{
//
char _msg[256] = {
};
scanf("%s",_msg);
//
if(0 == strcmp(_msg,"exit"))
{
tcp->CloseSocket();
printf("
");
break;
}
else if(0 == strcmp(_msg,"login"))
{
//
Login _login;
strcpy(_login.UserName,"hbxxy");
strcpy(_login.PassWord,"123456");
tcp->SendData(&_login);
}
else if(0 == strcmp(_msg,"logout"))
{
//
Logout _logout;
strcpy(_logout.UserName,"hbxxy");
tcp->SendData(&_logout);
}
else
{
printf("
");
}
}
}
int main()
{
printf("Welcome
");
// tcp
TcpClient *tcp1 = new TcpClient();
// socket
tcp1->InitSocket();
//
tcp1->Connect("127.0.0.1",8888);
// UI
std::thread t1(_cmdThread,tcp1);
t1.detach();//
//
while(tcp1->IsRun())
{
tcp1->OnRun();
}
//
tcp1->CloseSocket();
return 0;
}
2.サービス側
TcpServer.hpp
#ifndef _TcpServer_hpp_
#define _TcpServer_hpp_
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
#include
#pragma comment(lib,"ws2_32.lib")// windows
#else
#include //selcet
#include //uni std
#include
#define SOCKET int
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif
//
enum cmd
{
CMD_LOGIN,//
CMD_LOGINRESULT,//
CMD_LOGOUT,//
CMD_LOGOUTRESULT,//
CMD_NEW_USER_JOIN,//
CMD_ERROR//
};
//
struct DataHeader
{
short cmd;//
short date_length;//
};
// 1
struct Login : public DataHeader
{
Login()//
{
this->cmd = CMD_LOGIN;
this->date_length = sizeof(Login);
}
char UserName[32];//
char PassWord[32];//
};
// 2
struct LoginResult : public DataHeader
{
LoginResult()//
{
this->cmd = CMD_LOGINRESULT;
this->date_length = sizeof(LoginResult);
}
int Result;
};
// 3
struct Logout : public DataHeader
{
Logout()//
{
this->cmd = CMD_LOGOUT;
this->date_length = sizeof(Logout);
}
char UserName[32];//
};
// 4
struct LogoutResult : public DataHeader
{
LogoutResult()//
{
this->cmd = CMD_LOGOUTRESULT;
this->date_length = sizeof(LogoutResult);
}
int Result;
};
// 5
struct NewUserJoin : public DataHeader
{
NewUserJoin()//
{
this->cmd = CMD_NEW_USER_JOIN;
this->date_length = sizeof(NewUserJoin);
}
char UserName[32];//
};
#include
class TcpServer
{
public:
//
TcpServer()
{
_sock = INVALID_SOCKET;
}
//
virtual ~TcpServer()
{
// socket
CloseSocket();
}
// socket 1
int InitSocket()
{
#ifdef _WIN32
// windows socket 2,x
WORD ver = MAKEWORD(2,2);
WSADATA dat;
if(0 != WSAStartup(ver,&dat))
{
return -1;//-1
}
#endif
// socket
if(INVALID_SOCKET != _sock)
{
printf("
" ,_sock);
CloseSocket();//
}
_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == _sock)
{
return 0;//0 socket
}
return 1;
}
// IP/
int Bind(const char* ip,unsigned short port)
{
//
if(INVALID_SOCKET == _sock)
{
InitSocket();
}
// IP
sockaddr_in _myaddr = {
};
_myaddr.sin_family = AF_INET;//IPV4
_myaddr.sin_port = htons(port);//
#ifdef _WIN32
if(ip)//ip
{
_myaddr.sin_addr.S_un.S_addr = inet_addr(ip);//IP
}
else
{
_myaddr.sin_addr.S_un.S_addr = INADDR_ANY;//IP
}
#else
if(ip)//ip
{
_myaddr.sin_addr.s_addr = inet_addr(ip);//IP
}
else
{
_myaddr.sin_addr.s_addr = INADDR_ANY;//IP
}
#endif
if(SOCKET_ERROR == bind(_sock,(sockaddr*)&_myaddr,sizeof(sockaddr_in)))//socket ( )sockaddr
{
printf("
");
return 0;
}
else
{
printf("
%d
",port);
return 1;
}
}
//
int Listen(int n)
{
//
if(INVALID_SOCKET == _sock)
{
printf(" IP
");
return 0;
}
//
if(SOCKET_ERROR == listen(_sock,n))//
{
printf("
");
return 0;
}
else
{
printf("
");
return 1;
}
}
//
int Accept()
{
//
sockaddr_in _clientAddr = {
};// sockadd
int _addr_len = sizeof(sockaddr_in);// sockadd
SOCKET _temp_socket = INVALID_SOCKET;//
#ifdef _WIN32
_temp_socket = accept(_sock,(sockaddr*)&_clientAddr,&_addr_len);//
#else
_temp_socket = accept(_sock,(sockaddr*)&_clientAddr,(socklen_t*)&_addr_len);//
#endif
if(INVALID_SOCKET == _temp_socket)//
{
printf(" , SOCKET
" ,_temp_socket);
return 0;
}
else
{
printf("
IP :%s
", inet_ntoa(_clientAddr.sin_addr));
//
NewUserJoin _user_join;
strcpy(_user_join.UserName,inet_ntoa(_clientAddr.sin_addr));
for(int n=0;n<_clients.size();++n)
{
send(_clients[n],(const char*)&_user_join,sizeof(NewUserJoin),0);
}
//
_clients.push_back(_temp_socket);
return 1;
}
}
// socket
void CloseSocket()
{
if(INVALID_SOCKET != _sock)
{
#ifdef _WIN32
// socket
for(int n=0; n<_clients.size(); ++n)
{
closesocket(_clients[n]);
}
// socket
closesocket(_sock);
// windows socket
WSACleanup();
#else
// socket
for(int n=0; n<_clients.size(); ++n)
{
close(_clients[n]);
}
// socket/LINUX
close(_sock);
#endif
_sock = INVALID_SOCKET;
}
}
//
bool OnRun()
{
if(IsRun())
{
fd_set _fdRead;//
fd_set _fdWrite;
fd_set _fdExcept;
FD_ZERO(&_fdRead);//
FD_ZERO(&_fdWrite);
FD_ZERO(&_fdExcept);
FD_SET(_sock,&_fdRead);//
FD_SET(_sock,&_fdWrite);
FD_SET(_sock,&_fdExcept);
timeval _t = {
2,0};//select
SOCKET _maxSock = _sock;// socket
// read
for(int n=_clients.size()-1; n>=0; --n)
{
FD_SET(_clients[n],&_fdRead);
if(_maxSock < _clients[n])
{
_maxSock = _clients[n];
}
}
//select select
int _ret = select(_maxSock+1,&_fdRead,&_fdWrite,&_fdExcept,&_t);
if(_ret<0)
{
printf("select
");
CloseSocket();
return false;
}
if(FD_ISSET(_sock,&_fdRead))// socket
{
FD_CLR(_sock,&_fdRead);//
Accept();//
}
// socket
for(int n=0; n<_clients.size(); ++n)
{
if(FD_ISSET(_clients[n],&_fdRead))
{
if(-1 == RecvData(_clients[n]))//
{
std::vector<SOCKET>::iterator iter = _clients.begin()+n;//
if(iter != _clients.end())//
{
_clients.erase(iter);//
}
}
}
}
//printf("
");
return true;
}
return false;
}
//
bool IsRun()
{
return _sock != INVALID_SOCKET;
}
//
int SendData(DataHeader *_head,SOCKET _temp_socket)
{
if(IsRun() && _head)
{
send(_temp_socket,(const char*)_head,_head->date_length,0);
return 1;
}
return 0;
}
//
int RecvData(SOCKET _temp_socket)//
{
//
char buffer[4096] = {
};
//
int _buf_len = recv(_temp_socket,buffer,sizeof(DataHeader),0);
DataHeader *_head = (DataHeader*)buffer;
if(_buf_len<=0)
{
printf("
");
return -1;
}
recv(_temp_socket,buffer+sizeof(DataHeader),_head->date_length-sizeof(DataHeader),0);
//
NetMsg(_head,_temp_socket);
return 0;
}
//
void NetMsg(DataHeader *_head,SOCKET _temp_socket)
{
printf(" , :%d, :%d
",_head->cmd,_head->date_length);
switch(_head->cmd)
{
case CMD_LOGIN://
{
Login *_login = (Login*)_head;
/*
*/
printf("%s
:%s
",_login->UserName,_login->PassWord);
LoginResult *_result = new LoginResult;
_result->Result = 1;
SendData(_result,_temp_socket);
}
break;
case CMD_LOGOUT://
{
Logout *_logout = (Logout*)_head;
/*
*/
printf("%s
",_logout->UserName);
LogoutResult *_result = new LogoutResult();
_result->Result = 1;
SendData(_result,_temp_socket);
}
break;
default://
{
_head->cmd = CMD_ERROR;
_head->date_length = 0;
SendData(_head,_temp_socket);
}
break;
}
}
private:
SOCKET _sock;
std::vector<SOCKET> _clients;// socket
};
#endif
server_test.cpp
#include"TcpServer.hpp"
int main()
{
printf("Welcome
");
// tcp
TcpServer *tcp1 = new TcpServer();
// socket
tcp1->InitSocket();
// IP
tcp1->Bind(NULL,8888);
//
tcp1->Listen(5);
//
while(tcp1->IsRun())
{
tcp1->OnRun();
}
//
tcp1->CloseSocket();
printf(" , ");
getchar();
return 0;
}