Winsockプログラミング例---TCP&UDP


0 x 1 TCPベースの通信
1、サービス側
1.1基本プロセスを作成TCPサービス側のプログラムが呼び出す必要がある関数プロセスを作成する:
  • 初期化関数ライブラリ>>WSAstartup()
  • ソケットの作成>>socket()
  • バインドソケット>>bind()
  • リスニングポート>>listen()
  • 接続リクエストの取得>>accept()
  • 送信または受信データ>>send()
  • Winsockライブラリの解放>>WSACLeanup()
  • 1.2コード実装
    (1)関数ライブラリの初期化
    WSADATA wsaData; WSAStartup(MAKEWORD(2,2),&wsaData);
    説明:WSAstartupのパラメータ1->winsockライブラリのバージョン番号を初期化します.パラメータ2->はWSADATAのポインタを指し、この構造体はWSAstartup関数呼び出し後にWindowsSocketsデータを返すために使用されます.この初期化関数はプログラムの先頭で呼び出され、プログラムではWinsock関連のすべてのAPI関数を使用することができる.(2)ソケットの作成
    SOCKET sListen = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    

    説明:socket()関数パラメータ1->プロトコルファミリーを指定し、windowsの下で2つ使用します.AF_INET,PF_INET、この2つのマクロはWinsock 2にあります.hの定義は同じである.一般的にsocket()関数を呼び出すときにPF_を使用するべきですINET、アドレス設定時にAF_を使用INET. パラメータ2->新しいソケット記述子のタイプを指定します.一般的に使用されるのは3つで、それぞれSOCK_です.STREAM,SOCK_DGRAMとSOCK_RAWは、ストリームソケット、パケットソケット、元のプロトコルインタフェースです.パラメータ3->アプリケーションで使用される通信プロトコル、使用可能なIPPROTO_を指定します.TCP、IPPROTO_UDP,IPPROTO_ICMPなど.このパラメータは、パラメータ2の値に基づいて選択されます.ここでパラメータ2はSOCK_を使用していますSTREAMなのでパラメータ3はIPPROTO_を使用TCP. (3)バインドソケットとアドレス情報
    struct sockaddr_in ServerAddr; 
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.41.1");  //      IP        
    ServerAddr.sin_port = htons(1234);                           //htons                   
    bind(sListen,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
    

    説明:socket()関数は、新しいソケット記述子を作成できますが、ネットワークリソースの準備をする記述子にすぎません.本当にネットワークで通信するには、ローカルのアドレスとローカルのポート番号情報が必要です.bind関数により情報のバインドが行われ,bind関数の3つのパラメータの中で最も重要なのはパラメータ2である.これはsockaddrの構造体で、この構造体は16バイトあり、この構造体の前にsockaddr_を使用します.in,bind関数にアドレスとポートを指定する場合sockaddr_in構造体は、対応する内容を充填する.
    Struct sockaddr_in{
    	Short sin_family;
    	u_short sin_port;
    	struct in_addr sin_addr;
    	char sin_zero[8];
    };
    

    ここではこの構造体のsinをfamilyメンバー、その値は3種類あります:AF_UNIX(ネイティブ通信)AF_INET(TCP/IP - IPv4) AF_INET 6(TCP/IP–IPv 6)(4)リスニングポート
    listen(sListen,SOMAXCONN);
    

    説明:パラメータ2->システムの各ポートで最大のリスニングキューの長さを定義します(5)接続要求の取得
    sockaddr_in ClientAddr;
    int nSize = sizeof(ClientAddr);
    SOCKET sClient = accept(sLisent,(SOCKADDR *)&ClientAddr,&nSize);
    

    説明:acceptはリクエストキューから接続情報を取得し、新しいソケット記述子を作成し、クライアントアドレスを取得します.パラメータ1−>リスニング側ソケット記述子パラメータ2−>sockaddr構造体へのポインタは、クライアントのアドレス情報を返すために使用される.パラメータ3->クライアントsockaddr構造体のサイズ(6)ここでサービス側の操作は基本的に完了し,クライアントの接続を待つだけでデータ伝送が可能になる.
    1.3完全なコード
    #include 
    #include 
    #pragma comment(lib,"ws2_32")
    int main()
    {
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(2,2),&wsaData);
    	//     
    	SOCKET sListen = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    	// sockaddr_in       ,     
    	struct sockaddr_in ServerAddr; 
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.41.1");  //      IP        
    	ServerAddr.sin_port = htons(1234);                           //htons                   
    	
    	//          
    	bind(sListen,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
    	//    
    	listen(sListen,SOMAXCONN);
    	//      
    	sockaddr_in ClientAddr;
    	int nSize = sizeof(ClientAddr);
    	
    	SOCKET sClient = accept(sListen,(SOCKADDR *)&ClientAddr,&nSize);
    	//        IP      
    	printf("ClientIP=%s:%d\r
    "
    ,inet_ntoa(ClientAddr.sin_addr),ntohs(ClientAddr.sin_port)); //ntohs() , 16 // char szMsg[MAXBYTE] = {0}; lstrcpy(szMsg,"Hello Client!\r
    "
    ); send(sClient,szMsg,strlen(szMsg)+sizeof(char),0); //strlen sizeof // recv(sClient,szMsg,MAXBYTE,0); printf("Client Msg :%s \r
    "
    ,szMsg); WSACleanup(); return 0; }

    2、クライアント
    2.1基本プロセスクライアントとサービス側が呼び出すAPIは基本的に同じです:WSAstartup()->socket()->connect()->send()/recv()->closesocket()->WSAcleanup()2.2コード実装クライアントはソケットを作成してsockaddrを埋め込むだけです.in構造体のアドレスやポートなどの情報でよい.
    struct sockaddr_in ServerAddr;
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.41.1");
    ServerAddr.sin_port = htons(1234);
    

    ここに入力される情報は、接続が必要なサービス側の情報です.
    2.3完全コード
    #include 
    #include 
    #pragma comment (lib,"ws2_32")
    int main()
    {
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(2,2),&wsaData);
    	
    	//     
    	SOCKET sServer = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    
    	// sockaddr_in       、     
    	struct sockaddr_in ServerAddr;
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.41.1");
    	ServerAddr.sin_port = htons(1234);
    	
    	//      
    	connect(sServer,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
    	
    	char szMsg[MAXBYTE] = {0};
    
    	//    
    	recv(sServer,szMsg,MAXBYTE,0);
    	printf("Server Msg: %s \r
    "
    ,szMsg); // lstrcpy(szMsg,"Hello Server!!!\r
    "
    ); send(sServer,szMsg,sizeof(szMsg)+sizeof(char),0); WSACleanup(); return 0; }

    0 x 2 UDPベースの通信
    1、サービス側
    UDPプロトコルベースのサービス・エンド・プログラムは、ポートの傍受やリクエスト接続の待機を行わないため、UDPプロトコルのサービス・エンド・プログラムは短くなります.
    #include 
    #include 
    #pragma comment (lib,"ws2_32")
    int main()
    {
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(2,2),&wsaData);
    
    	//     
    	SOCKET sServer = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
    	// sockaddr_in       、     
    	struct sockaddr_in ServerAddr;
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.41.1");
    	ServerAddr.sin_port = htons(1245);  //htons                   
    	//          
    	bind(sServer,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
    	//    
    	char szMsg[MAXBYTE] = {0};
    	struct sockaddr_in ClientAddr;
    	int nSize = sizeof(ClientAddr);
    	recvfrom(sServer,szMsg,MAXBYTE,0,(SOCKADDR *)&ClientAddr,&nSize);
    	printf("Client Msg:%s \r
    "
    ,szMsg); printf("ClientIP = %s:%d\r
    "
    ,inet_ntoa(ClientAddr.sin_addr),ntohs(ClientAddr.sin_port)); // lstrcpy(szMsg,"Hello Client,this is Server!\r
    "
    ); nSize = sizeof(ClientAddr); sendto(sServer,szMsg,strlen(szMsg)+sizeof(char),0,(SOCKADDR *)&ClientAddr,nSize); WSACleanup(); return 0; }

    2、クライアント
    UDPクライアントベースのコードは、TCPプロトコルのクライアントコードに対してconnect()関数を呼び出して接続する必要がなく、TCPプロトコルの「3回の握手」のプロセスを省き、サーバに直接データを送信することができる.
    #include 
    #include 
    #pragma comment(lib,"ws2_32")
    
    int main()
    {
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(2,2),&wsaData);
    	//     
    	SOCKET sClient = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
    	// sockaddr_in       、     
    	struct sockaddr_in = ServerAddr;
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.S_un.S_addr = inet_addr("10.10.30.12");
    	ServerAddr.sin_port = htons(1234);
    	
    	//    
    	char szMsg[MAXBYTE] = {0};
    	lstrcpy(szMsg,"Hello Server This is Client !");
    	int nSize = sizeof(ServerAddr);
    	sendto(sClient,szMsg,strlen(szMsg)+sizeof(char),0,(SOCKADDR *)&ServerAddr,nSize);
    	//    
    	nSize = sizeof(ServerAddr);
    	recvfrom(sClient,szMsg,strlen(szMsg)+sizeof(char),0,(SOCKADDR*)&ServerAddr,nSize);
    	printf("Server Msg:%s \r
    "
    ,szMsg); WSACleanup(); return 0; }

    先輩のブログ:https://blog.roachs.cn/