C++ネットワークプログラミング学習:ネットワークデータメッセージの送受信


ネットワークプログラミング学習レコード
  • 使用言語はC/C+
  • ソースコードサポートプラットフォームは、Windows
  • 笔记一:基础TCP服务端/クライアント 点我跳转笔记二:ネットワークデータメッセージの送受信 点我跳转笔记三:selectネットワークモデル 点我跳转笔记四:プラットフォームをまたいでWindowsをサポート、Linuxシステム 点我跳转笔记5:ソースコードのパッケージ 点我跳转笔记6:バッファオーバーフローと粘着包分包 点我跳转笔记7:サービス端マルチスレッド分离业务処理高负荷 点我跳转笔记
    ノート2
  • ネットワークプログラミング学習記録
  • 一、ネットワークデータメッセージのフォーマット定義
  • 二、パケットヘッダとパケットデータを別々に送受信
  • 1.要約
  • 2.コードおよびその詳細なコメント
  • 2.1サービス側コード
  • 2.2クライアントコード

  • 三、分割送受信メッセージデータを一次送受信に変更
  • 1.構想
  • 2.コードおよびその詳細なコメント
  • 2.1サービス側コード
  • 2.2クライアントコード


  • 一、ネットワークデータメッセージのフォーマット定義
  • メッセージには2つの部分があり、パケットヘッダとパケットは、ネットワークメッセージの基本ユニットである.
  • ヘッダ:今回のメッセージパケットのサイズを記述し、パケットデータの役割を記述する.
  • パッケージ:転送する必要があるデータが含まれています.

  •   このデータ構造によれば,パケットヘッダの内容に基づいて,パケット体のデータを柔軟に処理することができる.
    二、包頭と包体データを別々に送受する
    1.概括
      上記のネットワークデータメッセージの定義を通じて、簡単に考えることができます.
  • 送信側は2回のsend操作を行い、1回目のsendはパケットヘッダを送信し、2回目のsendはパケット体を送信し、ネットワークデータメッセージの送信を実現することができる.
  • 受信側は2回のrecv操作を行い、1回目のrecvはパケットヘッダを受信し、2回目のrecvはパケット体を受信し、パケットヘッダの内容に基づいてデータ処理を行い、ネットワークデータメッセージの受信を実現することができる.

  • 以上の操作により、ネットワークデータメッセージの送受信を実現できます.
    2.コードとその詳細なコメント
    2.1サービス側コード
    #define WIN32_LEAN_AND_MEAN
    
    #include
    #include
    #include
    
    #pragma comment(lib,"ws2_32.lib")//         windows   
    
    using namespace std; 
     
    //         
    enum cmd 
    {
         
    	CMD_LOGIN,//   
    	CMD_LOGOUT,//   
    	CMD_ERROR//   
    };
    //       
    struct DateHeader 
    {
         
    	short cmd;//  
    	short date_length;//     	
    };
    //  1           
    struct Login
    {
         
    	char UserName[32];//    
    	char PassWord[32];//   
    };
    //  2          
    struct LoginResult 
    {
         
    	int Result;
    };
    //  3          
    struct Logout
    {
         
    	char UserName[32];//    
    };
    //  4          
    struct LogoutResult 
    {
         
    	int Result;
    };
     
    int main() 
    {
         
    	//  windows socket 2,x   windows   
    	WORD ver = MAKEWORD(2,2);//WinSock     
    	WSADATA dat;//        WSAStartup        Socket   
    	if(0 != WSAStartup(ver,&dat))//        0 
    	{
         
    		return 0;
    	}
    	
    	//    socket 
    	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//IPV4       TCP   
    	if(INVALID_SOCKET == _mysocket)//     
        {
            
            return 0;  
        } 
        
    	//       IP   
    	sockaddr_in _myaddr = {
         };//  sockaddr     sockaddr_in                    
    	_myaddr.sin_family = AF_INET;//IPV4
    	_myaddr.sin_port = htons(8888);//   host to net unsigned short
    	_myaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//     INADDR_ANY          
    	if(SOCKET_ERROR == bind(_mysocket,(sockaddr*)&_myaddr,sizeof(sockaddr_in)))//socket (    )sockaddr          
    	{
         
    		cout<<"     "<<endl;
    	}
    	else
    	{
         
    		//cout<
    	}
    	
    	//      
    	if(SOCKET_ERROR == listen(_mysocket,5))//            
    	{
         
    		cout<<"    "<<endl;
    	}
    	else
    	{
         
    		//cout<
    	}
    	
    	//         
    	sockaddr_in _clientAddr = {
         };//  sockadd           
    	int _addr_len = sizeof(sockaddr_in);//  sockadd      
    	SOCKET _temp_socket = INVALID_SOCKET;//         
    	
    	_temp_socket = accept(_mysocket,(sockaddr*)&_clientAddr,&_addr_len);//                   
    	if(INVALID_SOCKET == _temp_socket)//     
    	{
         
    		cout<<"        Socket"<<endl;
    	}
    	else
    	{
         
    		cout<<"      "<<endl; 
    		printf("IP   :%s 
    "
    , inet_ntoa(_clientAddr.sin_addr)); } while(true) { // DateHeader _head = { }; int _buf_len = recv(_temp_socket,(char*)&_head,sizeof(DateHeader),0); if(_buf_len<=0) { printf("
    "
    ); break; } printf(" , :%d, :%d
    "
    ,_head.cmd,_head.date_length); switch(_head.cmd) { case CMD_LOGIN:// { Login _login = { }; recv(_temp_socket,(char*)&_login,sizeof(Login),0); /* */ printf("%s
    "
    ,_login.UserName); send(_temp_socket,(char*)&_head,sizeof(DateHeader),0);// LoginResult _result = { 1}; send(_temp_socket,(char*)&_result,sizeof(LoginResult),0);// } break; case CMD_LOGOUT:// { Logout _logout = { }; recv(_temp_socket,(char*)&_logout,sizeof(Logout),0); /* */ printf("%s
    "
    ,_logout.UserName); send(_temp_socket,(char*)&_head,sizeof(DateHeader),0);// LogoutResult _result = { 1}; send(_temp_socket,(char*)&_result,sizeof(LogoutResult),0);// } break; default:// { _head.cmd = CMD_ERROR; _head.date_length = 0; send(_temp_socket,(char*)&_head,sizeof(DateHeader),0);// } break; } } // socket closesocket(_temp_socket); // socket closesocket(_mysocket); // windows socket WSACleanup(); printf(" , "); getchar(); return 0; }

    2.2クライアントコード
    #define WIN32_LEAN_AND_MEAN
    
    #include
    #include
    #include
    
    #pragma comment(lib,"ws2_32.lib")//         windows   
    
    using namespace std; 
     
    //         
    enum cmd 
    {
         
    	CMD_LOGIN,//   
    	CMD_LOGOUT,//   
    	CMD_ERROR//   
    };
    //       
    struct DateHeader 
    {
         
    	short cmd;//  
    	short date_length;//     	
    };
    //  1           
    struct Login
    {
         
    	char UserName[32];//    
    	char PassWord[32];//   
    };
    //  2          
    struct LoginResult 
    {
         
    	int Result;
    };
    //  3          
    struct Logout
    {
         
    	char UserName[32];//    
    };
    //  4          
    struct LogoutResult 
    {
         
    	int Result;
    };
     
    int main()
    {
         
    	//  windows socket 2,x   windows   
    	WORD ver = MAKEWORD(2,2);//WinSock     
    	WSADATA dat;//        WSAStartup        Socket   
    	if(0 != WSAStartup(ver,&dat))//        0 
    	{
         
    		return 0;
    	}
    	
    	//    socket 
    	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,0);//IPV4               
    	if(INVALID_SOCKET == _mysocket)//     
        {
            
            return 0;  
        } 
        
        //     
        sockaddr_in _sin = {
         };//sockaddr    
        _sin.sin_family = AF_INET;//IPV4
        _sin.sin_port = htons(8888);//         
    	_sin.sin_addr.S_un.S_addr =  inet_addr("127.0.0.1");//     IP 
    	if(SOCKET_ERROR == connect(_mysocket,(sockaddr*)&_sin,sizeof(sockaddr_in)))
    	{
         
    		cout<<"    "<<endl;
    		closesocket(_mysocket);
    	}
    	else
    	{
         
    		cout<<"    "<<endl; 
    	}
    	
    	while(true)
    	{
         
    		//     
    		char _msg[256] = {
         };
    		scanf("%s",_msg);
    		//     
    		if(0 == strcmp(_msg,"exit"))
    		{
         
    			break;
    		}
    		else if(0 == strcmp(_msg,"login"))
    		{
         
    			//   
    			Login _login = {
         "     ","123456"};
    			DateHeader _head = {
         CMD_LOGIN,sizeof(_login)};
    			send(_mysocket,(const char*)&_head,sizeof(_head),0);
    			send(_mysocket,(const char*)&_login,sizeof(_login),0);
    			//   
    			DateHeader _head2 = {
         }; 
    			LoginResult _result= {
         }; 
    			recv(_mysocket,(char*)&_head2,sizeof(DateHeader),0);
    			recv(_mysocket,(char*)&_result,sizeof(LoginResult),0);
    			printf("result:%d
    "
    ,_result.Result); } else if(0 == strcmp(_msg,"logout")) { // Logout _logout = { " "}; DateHeader _head = { CMD_LOGOUT,sizeof(_logout)}; send(_mysocket,(const char*)&_head,sizeof(_head),0); send(_mysocket,(const char*)&_logout,sizeof(_logout),0); // DateHeader _head2 = { }; LogoutResult _result= { }; recv(_mysocket,(char*)&_head2,sizeof(DateHeader),0); recv(_mysocket,(char*)&_result,sizeof(LogoutResult),0); printf("result:%d
    "
    ,_result.Result); } else { printf("
    "
    ); } } // socket closesocket(_mysocket); // windows socket WSACleanup(); return 0; }

    三、別々に送受信するメッセージデータを一回の送受信に変更する
    1.考え方
      上記より,send 2回とrecv 2回でメッセージの送受信が可能であることが分かるが,操作が面倒であり,DateHeaderヘッダ構造体を複数回宣言する必要があり,時間リソースを消費するだけでなく,エラーも発生しやすい.したがって,別々の送受信を1回の送受信に変更することを試みることができる.大まかな考え方は,メッセージの構造体を完備させ,パケットにヘッダ構造体を継承させたり,パケット構造体にパケットヘッダ構造体を1つ含ませたりすることである.これにより,メッセージの構造体を整備し,send操作を1回だけ行えば,すべてのメッセージデータを送信できる.  データ受信を行う場合、まずパケットヘッダサイズのデータを受信し、その後、パケットヘッダの内容に基づいて、次に受信するデータのサイズ、すなわち、受信総データサイズからパケットヘッダデータサイズを減算したデータを決定する.次にrecvを用いて残りのデータを受信する場合は,ポインタオフセットを用いて構造体パケットヘッダの受信(受信したため)をスキップし,パケットデータ位置に直接受信する.
    /*
                       :&_login+sizeof(DateHeader)
           :sizeof(Login)-sizeof(DateHeader)        
    */
    recv(_temp_socket,(char*)&_login+sizeof(DateHeader),sizeof(Login)-sizeof(DateHeader),0);
    

    2.コードとその詳細なコメント
    2.1サービス側コード
    #define WIN32_LEAN_AND_MEAN
    
    #include
    #include
    #include
    
    #pragma comment(lib,"ws2_32.lib")//         windows   
    
    using namespace std; 
     
    //         
    enum cmd 
    {
         
    	CMD_LOGIN,//   
    	CMD_LOGINRESULT,//     
    	CMD_LOGOUT,//   
    	CMD_LOGOUTRESULT,//     
    	CMD_ERROR//   
    };
    //       
    struct DateHeader 
    {
         
    	short cmd;//  
    	short date_length;//     	
    };
    // 1           
    struct Login : public DateHeader 
    {
         
    	Login()//      
    	{
         
    		this->cmd = CMD_LOGIN;
    		this->date_length = sizeof(Login); 
    	}
    	char UserName[32];//    
    	char PassWord[32];//   
    };
    // 2          
    struct LoginResult : public DateHeader 
    {
         
    	LoginResult()//      
    	{
         
    		this->cmd = CMD_LOGINRESULT;
    		this->date_length = sizeof(LoginResult); 
    	}
    	int Result;
    };
    // 3          
    struct Logout : public DateHeader 
    {
         
    	Logout()//      
    	{
         
    		this->cmd = CMD_LOGOUT;
    		this->date_length = sizeof(Logout); 
    	}
    	char UserName[32];//    
    };
    // 4          
    struct LogoutResult : public DateHeader 
    {
         
    	LogoutResult()//      
    	{
         
    		this->cmd = CMD_LOGOUTRESULT;
    		this->date_length = sizeof(LogoutResult); 
    	}
    	int Result;
    };
     
    int main() 
    {
         
    	//  windows socket 2,x   windows   
    	WORD ver = MAKEWORD(2,2);//WinSock     
    	WSADATA dat;//        WSAStartup        Socket   
    	if(0 != WSAStartup(ver,&dat))//        0 
    	{
         
    		return 0;
    	}
    	
    	//    socket 
    	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//IPV4       TCP   
    	if(INVALID_SOCKET == _mysocket)//     
        {
            
            return 0;  
        } 
        
    	//       IP   
    	sockaddr_in _myaddr = {
         };//  sockaddr     sockaddr_in                    
    	_myaddr.sin_family = AF_INET;//IPV4
    	_myaddr.sin_port = htons(8888);//   host to net unsigned short
    	_myaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//     INADDR_ANY          
    	if(SOCKET_ERROR == bind(_mysocket,(sockaddr*)&_myaddr,sizeof(sockaddr_in)))//socket (    )sockaddr          
    	{
         
    		cout<<"     "<<endl;
    	}
    	else
    	{
         
    		//cout<
    	}
    	
    	//      
    	if(SOCKET_ERROR == listen(_mysocket,5))//            
    	{
         
    		cout<<"    "<<endl;
    	}
    	else
    	{
         
    		//cout<
    	}
    	
    	//         
    	sockaddr_in _clientAddr = {
         };//  sockadd           
    	int _addr_len = sizeof(sockaddr_in);//  sockadd      
    	SOCKET _temp_socket = INVALID_SOCKET;//         
    	
    	_temp_socket = accept(_mysocket,(sockaddr*)&_clientAddr,&_addr_len);//                   
    	if(INVALID_SOCKET == _temp_socket)//     
    	{
         
    		cout<<"        Socket"<<endl;
    	}
    	else
    	{
         
    		cout<<"      "<<endl; 
    		printf("IP   :%s 
    "
    , inet_ntoa(_clientAddr.sin_addr)); } while(true) { // DateHeader _head = { }; int _buf_len = recv(_temp_socket,(char*)&_head,sizeof(DateHeader),0); if(_buf_len<=0) { printf("
    "
    ); break; } printf(" , :%d, :%d
    "
    ,_head.cmd,_head.date_length); switch(_head.cmd) { case CMD_LOGIN:// { Login _login; recv(_temp_socket,(char*)&_login+sizeof(DateHeader),sizeof(Login)-sizeof(DateHeader),0); /* */ printf("%s
    :%s
    "
    ,_login.UserName,_login.PassWord); LoginResult _result; _result.Result = 1; send(_temp_socket,(char*)&_result,sizeof(LoginResult),0);// } break; case CMD_LOGOUT:// { Logout _logout; recv(_temp_socket,(char*)&_logout+sizeof(DateHeader),sizeof(Logout)-sizeof(DateHeader),0); /* */ printf("%s
    "
    ,_logout.UserName); LogoutResult _result; _result.Result = 1; send(_temp_socket,(char*)&_result,sizeof(LogoutResult),0);// } break; default:// { _head.cmd = CMD_ERROR; _head.date_length = 0; send(_temp_socket,(char*)&_head,sizeof(DateHeader),0);// } break; } } // socket closesocket(_temp_socket); // socket closesocket(_mysocket); // windows socket WSACleanup(); printf(" , "); getchar(); return 0; }

    2.2クライアントコード
    #define WIN32_LEAN_AND_MEAN
    
    #include
    #include
    #include
    
    #pragma comment(lib,"ws2_32.lib")//         windows   
    
    using namespace std; 
     
    //         
    enum cmd 
    {
         
    	CMD_LOGIN,//   
    	CMD_LOGINRESULT,//     
    	CMD_LOGOUT,//   
    	CMD_LOGOUTRESULT,//     
    	CMD_ERROR//   
    };
    //       
    struct DateHeader 
    {
         
    	short cmd;//  
    	short date_length;//     	
    };
    // 1           
    struct Login : public DateHeader 
    {
         
    	Login()//      
    	{
         
    		this->cmd = CMD_LOGIN;
    		this->date_length = sizeof(Login); 
    	}
    	char UserName[32];//    
    	char PassWord[32];//   
    };
    // 2          
    struct LoginResult : public DateHeader 
    {
         
    	LoginResult()//      
    	{
         
    		this->cmd = CMD_LOGINRESULT;
    		this->date_length = sizeof(LoginResult); 
    	}
    	int Result;
    };
    // 3          
    struct Logout : public DateHeader 
    {
         
    	Logout()//      
    	{
         
    		this->cmd = CMD_LOGOUT;
    		this->date_length = sizeof(Logout); 
    	}
    	char UserName[32];//    
    };
    // 4          
    struct LogoutResult : public DateHeader 
    {
         
    	LogoutResult()//      
    	{
         
    		this->cmd = CMD_LOGOUTRESULT;
    		this->date_length = sizeof(LogoutResult); 
    	}
    	int Result;
    };
     
    int main()
    {
         
    	//  windows socket 2,x   windows   
    	WORD ver = MAKEWORD(2,2);//WinSock     
    	WSADATA dat;//        WSAStartup        Socket   
    	if(0 != WSAStartup(ver,&dat))//        0 
    	{
         
    		return 0;
    	}
    	
    	//    socket 
    	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,0);//IPV4               
    	if(INVALID_SOCKET == _mysocket)//     
        {
            
            return 0;  
        } 
        
        //     
        sockaddr_in _sin = {
         };//sockaddr    
        _sin.sin_family = AF_INET;//IPV4
        _sin.sin_port = htons(8888);//         
    	_sin.sin_addr.S_un.S_addr =  inet_addr("127.0.0.1");//     IP 
    	if(SOCKET_ERROR == connect(_mysocket,(sockaddr*)&_sin,sizeof(sockaddr_in)))
    	{
         
    		cout<<"    "<<endl;
    		closesocket(_mysocket);
    	}
    	else
    	{
         
    		cout<<"    "<<endl; 
    	}
    	
    	while(true)
    	{
         
    		//     
    		char _msg[256] = {
         };
    		scanf("%s",_msg);
    		//     
    		if(0 == strcmp(_msg,"exit"))
    		{
         
    			break;
    		}
    		else if(0 == strcmp(_msg,"login"))
    		{
         
    			//   
    			Login _login;
    			strcpy(_login.UserName,"     ");
    			strcpy(_login.PassWord,"123456");
    			send(_mysocket,(const char*)&_login,sizeof(_login),0);
    			//   
    			LoginResult _result; 
    			recv(_mysocket,(char*)&_result,sizeof(LoginResult),0);
    			printf("result:%d
    "
    ,_result.Result); } else if(0 == strcmp(_msg,"logout")) { // Logout _logout; strcpy(_logout.UserName," "); send(_mysocket,(const char*)&_logout,sizeof(_logout),0); // LogoutResult _result; recv(_mysocket,(char*)&_result,sizeof(LogoutResult),0); printf("result:%d
    "
    ,_result.Result); } else { printf("
    "
    ); } } // socket closesocket(_mysocket); // windows socket WSACleanup(); return 0; }