「コン・イージのガウン」に焦点を当てるのではなく、ソケットとは何かを見てみましょう

コン・イーはすでに魯迅の作品の登場人物であり、貧しく、学者を象徴する長いガウンを着ています。最近、誰もが「現代のコン・イジ」と呼んでいます。

ソケットの概念
ソケット自体に「ソケット」という意味があり、Linux 環境では、プロセス間のネットワーク通信を表すために使用される特殊なファイル タイプです。本質は、バッファの助けを借りてカーネルによって形成された疑似ファイルです。
もちろんファイルなので、ファイル記述子を使用してソケットを参照できます。パイプラインと同様に、Linux システムでそれらをファイルにパッケージ化する目的は、インターフェイスを統一して、ソケットの読み取りと書き込み、およびファイルの読み取りと書き込みの操作を一貫させることです。違いは、パイプは主にローカルのプロセス間通信に使用されるのに対し、ソケットは主にネットワーク プロセス間のデータ転送に使用されることです。
ソケットのカーネル実装は比較的複雑であり、学習の初期段階で深く研究するのには適していません。
TCP/IP プロトコルでは、「IP アドレス + TCP または UDP ポート番号」によって、ネットワーク通信におけるプロセスが一意に識別されます。「IPアドレス+ポート番号」がソケットに相当します。接続を確立しようとする 2 つのプロセスには、それぞれ識別するソケットがあり、これら 2 つのソケットによって形成されたソケット ペアが接続を一意に識別します。したがって、Socket を使用して、ネットワーク接続の 1 対 1 の関係を表すことができます。
ソケット通信の原理を下の図に示します。
ここに画像の説明を挿入
ネットワーク通信では、ソケットはペアで存在する必要があります。一方の端の送信バッファは、もう一方の端の受信バッファに対応します。送信バッファと受信バッファに同じファイル記述子を使用します。
TCP/IP プロトコルは最初に BSD UNIX で実装され、TCP/IP プロトコル用に設計されたアプリケーション層プログラミング インターフェイスはソケット API と呼ばれます。この章の主な内容はソケット API であり、主に TCP プロトコルの機能インターフェースを紹介し、最後に UDP プロトコルと UNIX ドメイン ソケットの機能インターフェースを紹介します。
ここに画像の説明を挿入

ソケット機能

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

ドメイン:
AF_INET これはソケットを生成するために使用されるプロトコルのほとんどで、伝送に TCP または UDP を使用し、IPv4 アドレスを使用します。
AF_INET6 上記と同様ですが、IPv6 アドレスを使用します。
UNIX および Linux システムで使用される AF_UNIX ローカル プロトコルは、通常、クライアントとサーバーが同じマシン上にある場合に使用されます。
タイプ:
SOCK_STREAM このプロトコルは、シーケンシャルで信頼性が高く、データ統合されたバイトストリームベースの接続です。これは最も使用されるソケット タイプであり、このソケットは送信に TCP を使用します。
SOCK_DGRAM このプロトコルはコネクションレスの固定長転送呼び出しです。プロトコルは信頼性が低く、接続に UDP を使用します。
SOCK_SEQPACKET このプロトコルは、送信用に固定長のデータ パケットを送信する信頼性の高い 2 線式接続です。パッケージは、読み取る前に完全に受け入れられる必要があります。
SOCK_RAW ソケット タイプは、単一のネットワーク アクセスを提供します。このソケット タイプは、ICMP パブリック プロトコルを使用します。(Ping と traceroute はこのプロトコルを使用します)
SOCK_RDM このタイプはめったに使用されず、ほとんどのオペレーティング システムでは実装されていません. データ リンク層用に提供されており、データ パケットの順序は保証されません.
protocol:
デフォルトのプロトコルを使用するには、0 を渡します。
戻り値:
成功: 新しく作成されたソケットを指すファイル記述子を返します。失敗: -1 を返し、errno を設定します。
socket() はネットワーク通信ポートを開きます. 成功すると, open() と同じようにファイル記述子を返します. アプリケーションは, ファイルの読み書きと同様に, ネットワーク上でデータを送受信するために読み書きを使用できます. socket() 呼び出しが失敗した場合は -1 を返します。IPv4 の場合、ドメイン パラメータは AF_INET として指定されます。TCP プロトコルの場合、type パラメータは SOCK_STREAM として指定され、ストリーム指向のトランスポート プロトコルを示します。UDP プロトコルの場合、type パラメータは SOCK_DGRAM として指定され、データグラム指向の伝送プロトコルを示します。protocol パラメータの導入は省略されています。0 を指定するだけです。

バインド機能

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd:
ソケット ファイル記述子。
addr:
IP アドレスとポート番号を構成します。
addrlen:
sizeof(addr) の長さ。
戻り値:
成功した場合は 0 を返し、失敗した場合は -1 を返し、errno を設定します。
通常、サーバー プログラムが監視するネットワーク アドレスとポート番号は固定されています. クライアント プログラムは、サーバー プログラムのアドレスとポート番号を知ると、サーバーへの接続を開始できます. したがって、サーバーは bind を呼び出して固定ネットワークをバインドする必要があります.アドレスとポート番号. ポート番号。
bind() の機能は、パラメーター sockfd と addr を一緒にバインドすることです。これにより、ネットワーク通信用のファイル記述子である sockfd が、addr によって記述されたアドレスとポート番号をリッスンします。前述のように、struct sockaddr * は一般的なポインター型ですが、addr パラメーターは実際にはさまざまなプロトコルの sockaddr 構造体を受け入れることができ、それらの長さが異なるため、構造体の長さを指定するには第 3 パラメーター addrlen が必要です。好き:

struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);

最初に構造全体をクリアし、次にアドレス タイプを AF_INET に設定し、ネットワーク アドレスを INADDR_ANY に設定します。サーバーには複数のネットワーク カードがあり、各ネットワーク カードも複数の IP アドレスにバインドされている可能性があるため、このマクロは任意のローカル IP アドレスを表します。 . 設定はすべての IP アドレスでリッスンでき、クライアントとの接続が確立されるまでどの IP アドレスを使用するかは決定されず、ポート番号は 6666 です。

リッスン機能

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);

sockfd:
ソケット ファイル記述子。
バックログ:
3 ウェイ ハンドシェイク キューを確立するためにキューに入れられた接続数と、確立されたばかりの 3 ウェイ ハンドシェイク キューの合計数。
システムのデフォルトのバックログを表示

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

典型的なサーバー プログラムは、同時に複数のクライアントにサービスを提供できます. クライアントが接続を開始すると、サーバーによって呼び出された accept() が戻り、接続を受け入れます. 接続を開始するクライアントが多数あり、サーバーに時間がない場合それらを処理するために、まだ受け入れていないクライアント端末は接続待機状態にあり、listen() は sockfd が待機状態にあることを宣言し、最大でバックログ クライアントが接続待機状態になることを許可し、それ以上の場合は無視します接続要求が受信されます。listen() は、成功すると 0 を返し、失敗すると -1 を返します。

受け入れ機能

#include <sys/types.h> 		/* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockdf:
ソケット ファイル記述子。
addr:
発信パラメータ。IP アドレスとポート番号を含むリンク クライアント アドレス情報を返します。
addrlen:
入出力パラメータ (value-result) を渡し、sizeof(addr) のサイズを渡します。関数が戻ると、実際に受け取ったアドレス構造のサイズを返します。
戻り値:
クライアントと通信するための新しいソケット ファイル記述子を正常に返します。-1 を返すのに失敗し、errno を設定します。
スリーウェイ ハンドシェイクが完了した後、クライアントが存在しない場合、サーバーは accept() を呼び出して接続を受け入れます。サーバーは accept() を呼び出します。クライアントからの接続要求がある場合、サーバーはブロックされ、クライアントが接続するまで待機します。addr は発信パラメータで、accept() は発信クライアントのアドレスとポート番号を返します。addrlen パラメータは、着信および発信パラメータ (value-result 引数) です。渡されるのは、バッファ オーバーフローの問題を回避するために呼び出し元によって提供されたバッファ addr の長さであり、渡されるのは、クライアント アドレスの実際の長さです。構造体 (呼び出し元によって提供されたバッファーがいっぱいにならない場合があります)。addr パラメータに NULL を渡すと、クライアントのアドレスを気にしないことを意味します。
サーバープログラムの構造は次のようになります。

while (1) {
    
    
	cliaddr_len = sizeof(cliaddr);
	connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
	n = read(connfd, buf, MAXLINE);
	......
	close(connfd);
}

全体が while 無限ループであり、各ループがクライアント接続を処理します。cliaddr_len は着信および発信パラメーターであるため、accept() を呼び出すたびに初期値を再割り当てする必要があります。accept() のパラメーター listenfd は、以前にリッスンしているファイル記述子であり、accept() の戻り値は別のファイル記述子 connfd であり、この connfd を介してクライアントと通信し、最後に connfd を閉じて切断します。再びループの先頭に戻ります. listenfd は引き続き accept のパラメータとして使用されます. accept() は、成功するとファイル記述子を返し、エラーの場合は -1 を返します。

接続機能

#include <sys/types.h> 					/* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockdf:
ソケット ファイル記述子。
addr:
IP アドレスやポート番号など、サーバー側のアドレス情報を指定する着信パラメーター。
addrlen:
パラメータを渡し、sizeof(addr) サイズを渡します。
戻り値:
成功した場合は 0 を返し、失敗した場合は -1 を返し、errno を設定します。
クライアントはサーバーに接続するために connect() を呼び出す必要があります. connect と bind のパラメータ形式は同じです. 違いは, bind のパラメータは自身のアドレスですが, connect のパラメータは相手のアドレスです. . connect() は、成功すると 0 を返し、エラーの場合は -1 を返します。

おすすめ

転載: blog.csdn.net/qq_43471489/article/details/130363405