以前、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++;
}
}