Linuxソケットプログラミング:プログラミングノート(1)

以前、LinuxでのネットワークプログラミングAPIとアドレス処理について説明しましたが、このブログでは主にいくつかの詳細を記録しています。
Linuxプログラミングでは、ネットワークプロセスがバッファからデータを読み取ることはわかっていますが、バッファについてはどうですか?受信したデータを連続メモリに保存するのですか、それともパケットの到着に従って保存するのですか?Linuxでは、ネットワークが受信したデータはパケットによってバッファリングされます。各ソケット構造には、受信リンクリスト、送信リンクリスト、異常リンクリストの3つのリンクリストがあります。対応するデータは、これらの3つのリンクされたリストに格納され、グループ(パケット)を1つの単位として基づいていますUDPは受信時に注意する必要があります。受信バッファを十分に大きくしてください。そうしないと、残りのデータがデフォルトで失われます。これはTCPには当てはまりません
以下は私の実験のソースコードです。クライアントはクライアント、サービスはサーバーです。

/*client.c*/
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc,char*argv[])
{
	struct sockaddr_in service,client;
	int fd,ret;
	char buf[40]={0};
	socklen_t addrlen = sizeof(client);
	
	fd = socket(AF_INET,SOCK_DGRAM,0);
	if(fd < 0){perror("socket");exit(-1);}
	memset(&service,0,sizeof(service));
	service.sin_family = AF_INET;
	service.sin_port = htons(5050);
	service.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	memcpy(buf,argv[1],strlen(argv[1]));
	
	while(1){
		ret = sendto(fd,buf,sizeof(buf),0,(struct sockaddr*)&service,addrlen);
		if(ret == -1){perror("sendto");close(fd);exit(-1);}
		sleep(1);
	}
	
	close(fd);
}

/*service.c*/
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc,char*argv[])
{
	struct sockaddr_in service,client;
	int fd,ret;
	char buf[40];
	socklen_t addrlen = sizeof(client);
	
	fd = socket(AF_INET,SOCK_DGRAM,0);
	if(fd < 0){perror("socket");exit(-1);}
	memset(&service,0,sizeof(service));
	service.sin_family = AF_INET;
	service.sin_port = htons(5050);
	service.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	ret = bind(fd, (struct sockaddr*)&service, sizeof(struct sockaddr));
	if(ret <0){perror("bind");exit(-1);}

	
	while(1){
		ret = recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&client,&addrlen);
		printf("%s string len %d\n",buf,ret);
		printf("recv ip %s port %d \n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));				
		memset(buf,0,sizeof(buf));
		sleep(2);
	}
	
	close(fd);
}

機能は非常にシンプルで、UDPのクライアントはサーバーにデータを送信しており、送信速度は受け入れよりも高速です。受信したデータをサーバー側で印刷します。

  • 実験的なプロセスは次のとおりです。2つのクライアントを同時に実行し、「12346567890」と「abcdefg」の2つの文字列をサーバーに送信します。サーバーで実行した後、2つの文字列が別々に受信され、互いにくっつかないことがわかりました。
    ここに画像の説明を挿入
    ここに画像の説明を挿入
  • クライアントの起動時に、送信されたデータがサーバーの直接バッファーよりも大きい場合、サーバーで受信されたデータはバッファー長のみであり、残りは失われます。この現象は、送信者が一度に30バイトのパケットを送信しますが、受信すると20回の1回の受信であり、残りの10バイトは次回の受信では取得できずに失われることがわかります。
    ここに画像の説明を挿入
    ここに画像の説明を挿入
    しかし、これはTCPでは起こりません、現象は以下の通りです。
    ここに画像の説明を挿入
    ここに画像の説明を挿入
  • 送信者がオフになった後も、サーバーは一定期間メッセージを読み取ることができます。これは、受信バッファがリンクリストを使用するため、一部のパケットをバッファできるためです。バッファをどれだけ小さくできるかは、自分で設定できます。
    多くの場所で見ることができるネットワークアドレスにコピーする際に使用されるINADDR_ANY、ネットワーク内の0,0の値でこのマクロがあり、これはこれで、ネットワーク上のこのホスト。したがって、このネットワークを表すために使用されます。このマクロは受信側でのみ使用でき、送信時には使用できません。ターゲットはネットワーク内ですべて0になることを許可されていないため、すべて0はお互いを見つけることができません。マルチネットワークカードデバイスでは、サーバーはこのマクロを使用することを好みます。すべてのポートのパケットを受信したい場合、各ポートのアドレス構成情報を1つずつ設定する必要がないため、特に便利です。
    ここに画像の説明を挿入
    ネットワークプログラミングの基本では、inet_aton、inet_addr、inet_network、inet_ntoaなど、ネットワークで頻繁に使用されるアドレス変換関数について説明します。これらの関数は、文字列型のドット付き10進および2進のIPデータを分割できます(一部はネットワークシーケンス変換)。ただし、バイナリIPポインタをドット付き10進文字列型に変換する関数はありません。ここでは、inet_ntoaと同じ機能を持つ関数inet_ntopを追加する必要があります。バイナリIPパラメータの形式のみが異なります。
       #include <arpa/inet.h>
       const char *inet_ntop(int af, const void *src,
                             char *dst, socklen_t size);
		/*af 指的是使用的IP版本,可以是AF_INET和AF_INET6,而srx则是二进制的IP地址指针,dst为点分十进制的IP地地,size表示的是dst的长度(字节数)*/

以下は、gethostbyname関数を使用してdnsの関数をシミュレートする方法です。ユーザーが入力したホスト名に応じて、IPアドレス、IPバージョンなどの対応する情報が取得されます。IPアドレスリストに格納されているIPアドレスがネットワークシーケンスであるgethostbyname関数を使用して取得したホスト情報は、使用中に置き換える必要があることに注意してください。

#include<stdio.h>
#include<netdb.h>
#include<arpa/inet.h>

int main(int argc,char *argv[])
{
    if(argc < 2){printf("please enter host name\n");return -1;}
    struct hostent *host = NULL;
    int i =0;
    char ip[30];
    host = gethostbyname(argv[1]);
    if(host == NULL){perror("gethostbyname");return -1;}
    printf("host name %s \n ",host->h_name);
    i = 0;
    while(host->h_aliases[i]){
	printf("aliases[%d]:%s \n",i+1,host->h_aliases[i]);
	i++;	
   }	
   printf("host addr type %s \n",host->h_addrtype==AF_INET?"AF_INET":"AF_INET6");
   printf("host addr length %d \n",host->h_length);
   i = 0;
   while(host->h_addr_list[i]){/*这里的IP地址列表为网络序,如果不使用这个函数,自己需要转换*/
	printf("host address[%d]: %s\n",i+1,inet_ntop(AF_INET,host->h_addr_list[i],ip,sizeof(ip)));
	i++;		
   }
}
元の記事を35件公開 Like1 Visits 1870

おすすめ

転載: blog.csdn.net/lzj_linux188/article/details/105298429