基本的なTCPソケットプログラミングフロー

基本的なプログラミングプロセスの概要

クライアントとサーバー間の通信を実現するには、クライアントとサーバーを一緒に完了する必要があります。その中で、TCPサーバーとクライアントのプログラミングプロセスを図に示します。ここに画像の説明を挿入します
最初にサーバーがソケットを作成し、次にバインドが通信ポートをバインドし、リッスンキューを作成します。その後、コミュニケーションのプロセスが始まりました。この時点で、サーバーは、tcpクライアントがイニシアチブを取り、接続を確立するための3ウェイハンドシェイクに接続するまで、受け入れ時にブロックされます。このとき、クライアントの書き込み機能がサーバーにリクエストを送信し、サーバーが読み取りを行ってリクエストを読み取り、処理します。処理が完了すると、サーバーの書き込み関数が呼び出されてクライアントに応答メッセージが送信され、クライアントは読み取りを通じて応答メッセージを受信します。この時点で、データ交換全体が終了し、クライアントはアクティブにシャットダウンできます。

クライアントとサーバーでのソケットプログラミング

ここに画像の説明を挿入します
ファミリは通常、IPV4プロトコルではAF_INETであり、IPv6プロトコルではAF_INET6です。タイプは、TCP伝送プロトコルではSOCK_STREAM、UDPプロトコルではSOCK_DGRAMです。通常、元のソケットで使用されていない限り、関数ソケットのパラメータプロトコルは0に設定されます。

クライアント接続機能は、サーバーとのリンクを確立します

TCPクライアントは、接続機能を使用してTCPサーバーとの接続を確立します。ここに画像の説明を挿入します
sockfdは、ソケット関数の戻り値です。2番目のパラメーターはソケットアドレス構造体へのポインターであり、3番目のパラメーターは構造体のサイズです。ここに画像の説明を挿入します
sin_portはポート番号、S_addrはサーバーネットワークのIPアドレスです。このプログラムを通じて、クライアントはクライアントのポートとIPに接続できます。つまり、リンクを確立できます。

バインドバインドソケットとIPポート

バインドは、ローカルプロトコルアドレスをソケットに割り当てます。ネットワークプロトコルの場合、プロトコルアドレスは32ビットIPv4アドレスまたは128ビットIPv6アドレスです。
ここに画像の説明を挿入します
最初のパラメーターはソケット関数の戻り値であり、2番目と3番目は接続関数で説明されているものと同じです。ここに画像の説明を挿入します
サーバー用とクライアント用の2つのソケットオブジェクトを確立します。

サーバーリッスンリッスンキュー

listenはTCPサーバーによってのみ呼び出され、主に2つの機能を
ここに画像の説明を挿入します
実行します。バックログはリンクの最大数を指します。特定のリスニングソケットに対して、カーネルは2つのキューを維持します
。1。リンクキューを完了するため
。2。未完了の接続キューのここに画像の説明を挿入します
バックログの前に、2つのキューの合計の最大値として定義されています。通常、テスト環境では、バックログを5に設定します。しかし、最新のサーバーには十分とは言えません。バックログを0に設定することはできません。これにより、プログラムに欠陥が発生します。他の人に接続させたくない場合は、このポートを閉じる必要があります。

サーバー側の受け入れ

Acceptはサーバーによって呼び出され、クライアントから送信された接続要求をリンクします。これにより、3つの手の波を介して接続が確立されます。ここに画像の説明を挿入します
受け入れの実行が成功した場合、戻り値はカーネルによって自動的に生成された新しい記述子であり、クライアントとのTCP接続を表すことに注意してください。この記述子は接続ソケットと呼ばれ、ソケット関数の戻り値はリスニングソケットと呼ばれます。リスニングソケットsockfdは、多くの場合、サーバープログラムで1つしか生成せず、常に存在します。接続されたソケットCは、クライアントとサーバーが3ウェイハンドシェイクを完了したことを意味します。クライアントが切断されると、Cソケットは閉じられます。
もちろん、C <0の場合、リンクの確立に失敗したことを意味し、クライアントが接続するのをブロックして待機します。ここに画像の説明を挿入します

書く和読む

書き込みと読み取りは2つの状態であり、それぞれ処理データと受信データを表します。たとえば、プログラムが通信する場合、通常、書き込みは送信システムコールで表され、読み取りは通常、受信システムコールで表されます。
クライアント側での送信と受信:サーバー側での送信と受信ここに画像の説明を挿入します
ここに画像の説明を挿入します

ソケットを閉じる閉じる

この時点で、TCPソケットのプログラミングプロセスは基本的に終了しており、ソケット記述子を閉じるだけで済みます。

実験結果

リンクを確立するためのスリーウェイハンドシェイク:ここに画像の説明を挿入します
データの読み取りとクライアントからのデータの送信を続行します:ここに画像の説明を挿入します
サーバーのソースコード:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

int main()
{
    
    
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	assert(-1!=sockfd);

	struct sockaddr_in saddr,caddr;
	memset(&saddr,0,sizeof(saddr));    //注意memset是取地址

	saddr.sin_family=AF_INET;
	saddr.sin_port=htons(6000);//主机转网络字节,网络是大段;
	saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

	int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
	assert(res!=-1);

	listen(sockfd,5);    //以完成3次握手队列长度是5


	while(1)
	{
    
    
		int len=sizeof(caddr);
		int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
		
		//这里是c也是套接字,类似与上面代码的sockfd;

		if(c<0)
		{
    
    
			continue;
		}
		printf("accept c=%d\n",c);     //链接套接子
		while(1)
		{
    
    
			char buff[128]={
    
    0};
			int n=recv(c,buff,127,0);
			//如果对方关闭了发送,recv返回0;-1是失败
			if(n<=0)
			{
    
    
				break;
			}
			printf("buff=%s\n",buff);
			send(c,"ok",2,0);
		}
		close(c);
	}
}



クライアントのソースコード:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

int main()
{
    
    
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	assert(sockfd!=-1);

	struct sockaddr_in saddr;
	memset(&saddr,0,sizeof(saddr));
	saddr.sin_family=AF_INET;
	saddr.sin_port=htons(6000);
	saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

	int res =connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
	assert(res!=-1);

	while(1)
	{
    
    
		char buff[128]={
    
    0};
		printf("input:\n");
		fgets(buff,128,stdin);

		if(strncmp(buff,"end",3)==0)
		{
    
    
			break;
		}
		send(sockfd,buff,strlen(buff),0);
		memset(buff,0,128);
		recv(sockfd,buff,128,0);
		printf("buff=%s\n",buff);
	}
	exit(0);
}

おすすめ

転載: blog.csdn.net/ALITAAAA/article/details/109413541