目次
TCP と UDP
トランスポート層で使用される主なプロトコル モデルは 2 つあります。1 つは TCP プロトコルで、もう 1 つは UDP プロトコルです。TCP プロトコルはネットワーク通信で支配的な役割を果たし、ネットワーク通信の大部分は TCP プロトコルを使用してデータ伝送を完了します。しかし、UDP はネットワーク通信において不可欠な通信手段でもあります。
TCP と比較すると、UDP 通信の形式はテキスト メッセージの送信に似ています。データ送信前に接続を確立して維持する必要はありません。データを取得することに集中してください。スリーウェイ ハンドシェイクのプロセスが省略され、通信速度が大幅に向上しますが、それに伴う通信の安定性と正確性は保証されません。したがって、UDP を「コネクションレスで信頼性の低いメッセージ配信」と呼びます。
では、よく知られている TCP と比較して、UDP の長所と短所は何ですか? 接続を作成する必要がないため、UDP オーバーヘッドが小さく、データ転送速度が速く、リアルタイム性が強いです。ビデオ会議やテレビ会議など、高いリアルタイム性が要求されるコミュニケーションの場で主に使用されます。しかし、信頼性の低いデータ伝送も伴い、伝送データの精度、伝送シーケンス、およびフローを制御および保証することはできません。したがって、通常の状況では、UDP プロトコルを使用してデータを送信しますが、データの正確性を保証するために、アプリケーション層に補助検証プロトコルを追加して、UDP の欠点を補う必要があります。信頼性の高いデータ伝送の目的。
TCP と同様に、UDP もバッファがいっぱいになった後にデータを受信すると、パケット損失が発生する可能性があります。TCP スライディング ウィンドウ メカニズムがないため、通常は次の 2 つの方法が使用されます。
1) サーバー アプリケーション層は、データの送信速度を制御するフロー制御を設計します。
2) setsockopt 関数を使用して、受信バッファーのサイズを変更します。
#include <sys/socket.h> int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen); int n = 220x1024; setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&n,sizeof(n));
C/S モデル UDP
UDP は接続を維持する必要がないため、プログラム ロジックは単純ですが、UDP プロトコルは信頼性が低く、通信の信頼性を確保するためのメカニズムをアプリケーション層で実装する必要があります。
コード例:
#include <string.h> #include <netinet/in.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <ctype.h> #define MAXLINE 80 #define SERV_PORT 8080 int main(void) { int n,i; struct sockaddr_in servaddr,cliaddr; socklen_t cliaddr_len; int sockfd; char str[INET_ADDRSTRLEN]; char buf[MAXLINE]; sockfd = socket(AF_INET,SOCK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); while(1) { cliaddr_len = sizeof(cliaddr); n = recvfrom(sockfd,buf,MAXLINE,0,(struct sockaddr *)&cliaddr,&cliaddr_len); if(n == -1) { perror("recvfrom error"); } printf("连接来自 %s 在端口 %d\n", inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port)); for(i=0;i<n;++i) { buf[i] = toupper(buf[i]); } n = sendto(sockfd,buf,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); if(n == -1) { perror("sendto error"); } } close(sockfd); return 0; }
#include <stdio.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <string.h> #include <ctype.h> #define MAXLINE 80 #define SERV_PORT 8080 int main(void) { int n; struct sockaddr_in servaddr; char str[INET_ADDRSTRLEN]; char buf[MAXLINE]; int sockfd; sockfd = socket(AF_INET,SOCK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr); while(fgets(buf,MAXLINE,stdin) != NULL) { n = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&servaddr,sizeof(servaddr)); if(n == -1) { perror("sendto error"); } n = recvfrom(sockfd,buf,MAXLINE,0,NULL,0); if(n == -1) { perror("recvfrom error"); } write(STDOUT_FILENO,buf,n); } close(sockfd); return 0; }
ブロードキャスト
int setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag)); //靴下の属性を変更
sockfd へのブロードキャスト権限を開く
マルチキャスト
マルチキャストは永続的または一時的です。マルチキャスト アドレスの中には、正式に割り当てられ、永続的なマルチキャスト グループと呼ばれるものがあります。永続的なマルチキャスト グループで変更されないのはその IP アドレスであり、グループ内のメンバーの構成は変更される可能性があります。永続的なマルチキャスト グループのメンバーは任意であり、0 であってもかまいません。永続的なマルチキャスト用に予約されていない IP マルチキャスト アドレスは、一時的なマルチキャスト グループで使用できます。
224.0.0.0 ~ 224.0.0.255 は予約済みマルチキャスト アドレス (永続アドレス) で、アドレス 224.0.0.0 は予約済みで割り当てられず、その他はルーティング プロトコルによって使用されます。
224.0.1.0~224.0.1.255はインターネット上で利用できる公開マルチキャストアドレスで、利用申請が必要です。
224.0.2.0 ~ 238.255.255.255 は、ユーザーが使用できるマルチキャスト アドレスです (一時的なアドレス、ネットワーク全体で有効)
239.0.0.0 ~ 239.255.255.255 は、特定のローカル範囲内でのみ有効なローカル管理マルチキャスト アドレスです。
ip adコマンドを使用して、ネットワーク カード番号の IP アドレスを表示できます。
コマンドを使用してネットワークカードを有効/無効にします sudo ifconfig etho up/down
if_nametoindex 関数コマンドを使用して、ネットワーク カードの名前に基づいてネットワーク カードのシリアル番号を取得します。
#include <net/if.h>
unsigned int if_nametoindex(const char *ifname);
コード例:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <unistd.h> #include <arpa/inet.h> #define SERVER_PORT 8080 #define CLIENT_PORT 9000 #define MAXLINE 1500 #define GROUP "239.0.0.2" //本地组播地址 /* struct ip_mreqn { struct in_addr imr_multiaddr; 组播组的IP struct in_addr imr_address; 本地IP int imr_ifindex; 网卡编号 }; */ int main(void) { int sockfd,i; struct sockaddr_in serveraddr,clientaddr; struct ip_mreqn group; char buf[MAXLINE] = "itcast\n"; sockfd = socket(AF_INET,SOCK_DGRAM,0); bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(SERVER_PORT); bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); //设置组地址 inet_pton(AF_INET,GROUP,&group.imr_multiaddr); //本地任意 IP inet_pton(AF_INET,"0.0.0.0",&group.imr_address); //eth0 group.imr_ifindex = if_nametoindex("eth0"); setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&group,sizeof(group)); //构造 client 地址和端口 bzero(&clientaddr,sizeof(clientaddr)); clientaddr.sin_family = AF_INET; inet_pton(AF_INET,GROUP,&clientaddr.sin_addr.s_addr); clientaddr.sin_port = htons(CLIENT_PORT); while(1) { sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&clientaddr,sizeof(clientaddr)); sleep(1); } close(sockfd); return 0; }
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/stat.h> #define SERVER_PORT 8080 #define MAXLINE 4096 #define CLIENT_PORT 9000 #define GROUP "239.0.0.2" //本地组播地址 int main() { struct sockaddr_in serveraddr,localaddr; int confd; ssize_t len; char buf[MAXLINE]; //定义组播结构体 struct ip_mreqn group; confd = socket(AF_INET,SOCK_DGRAM,0); //初始化本地端地址 bzero(&localaddr,sizeof(localaddr)); localaddr.sin_family = AF_INET; inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr.s_addr); localaddr.sin_port = htons(CLIENT_PORT); bind(confd,(struct sockaddr *)&localaddr,sizeof(localaddr)); //设置组地址 inet_pton(AF_INET,GROUP,&group.imr_multiaddr); //本地任意 inet_pton(AF_INET,"0.0.0.0",&group.imr_address); //eth0 group.imr_ifindex = if_nametoindex("eth0"); setsockopt(confd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group)); while(1) { len = recvfrom(confd,buf,sizeof(buf),0,NULL,0); write(STDERR_FILENO,buf,len); } close(confd); return 0; }
setsockopt の役割
1. ポートの多重化
2.バッファサイズを設定する
3.ブロードキャスト権限を開く
4.マルチキャスト許可を開く