トランスポート層プロトコル:TCP/UDPプロトコル
TCP : 伝送制御プロトコル、コネクション指向、信頼性の高い伝送、バイトストリーム指向。
——リアルタイムのパフォーマンスよりもセキュリティを必要とするシナリオ (ファイル転送など) に適用されます。
UDP : ユーザー データグラム プロトコル、コネクションレス、信頼性が低く、データグラム指向。
——セキュリティよりもリアルタイム パフォーマンスが必要なシナリオ (ビデオ、オーディオなど) に適用されます。
UDP操作プロセス:
サーバ:
① ソケットを作成します。
カーネル内にソケット構造を作成して、プロセスをネットワーク カードに関連付けます。
②ソケットのバインドアドレス情報:
作成したソケット構造体のソースアドレス情報を記述します。
③ データ受信:
ソケット受信バッファからデータを取り出します。
④ データをサーバーに送信します。
送信するデータを送信バッファに入れます。
⑤ ソケットを閉じます。
クライアント:
① ソケットを作成します。
②ソケットのバインドアドレス情報:
クライアントは、アドレスを積極的にバインドすることを推奨しません。バインド後、プログラムは 1 つのアドレスのみを起動できるため、クライアントは固定アドレスを使用する必要がありません。
③サーバーにデータを送信:
データを送信する前にソケットが指定されたアドレスにバインドされていない場合、システムはバインドする適切なアドレス情報を自動的に選択します。
④ データを受信します。
⑤ ソケットを閉じます。
TCPの動作プロセス
リスニングソケット(新しい接続リクエストの処理のみ) および通信ソケット(通信のみ);
最初に接続してから通信する必要があるため、ブロードキャスト操作はありません。
サーバ
① ソケットを作成します。
カーネル内にソケット構造を作成して、プロセスをネットワーク カードに関連付けます。
②ソケットのバインドアドレス情報:
作成したソケット構造体のソースアドレス情報を記述します。
③モニタリング開始:
現在のソケットが接続要求を処理できることをサーバーに伝えます (リッスンしているソケットはリッスン状態に変換されます)。
クライアントが接続要求を送信すると、サービスは指定されたクライアントと通信するための新しいソケットを作成します(ソケットは通信ソケットであり、状態は確立されています (準備完了))。
④ 新しい接続を取得します。
完了した接続キューから、指定されたソケットと指定されたクライアント間の通信に対応する新しいソケット記述子を取り出します。
⑤ データの送受信。
⑥ソケットを閉じます。
クライアント
① ソケットを作成します。
②ソケットのバインドアドレス情報(非推奨)。
③サーバーへの接続を開始します。
接続後、クライアント TCP は完全な 5 つ組も保存します。
④ データの送受信。
⑤ ソケットを閉じます。
インターフェースの紹介
#include<sys/socket.h>
#include<netinet/in.h>
ソケットを作成する
int socket(int domain, int type, int protocol);
//domain:地址域类型——AF_INET & AF_INET6;
//type:套接字类型——SOCK_STREAM & SOCK_DGRAM;
//protocol:协议类型——IPPROTO_TCP & IPPROTO_UDP (可以默认给0);
//返回值:成功返回一个套接字描述符,失败返沪-1;
バインドアドレス情報
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
//sockfd:创建套接字返回的描述符;
//addr:要绑定的地址信息(这是一个通用描述,根据前两个字节的内容使用统一的接口绑定不同的地址结构,还有端口信息、IP地址,IPV4为struct sockaddr_in, IPV6为struct sockaddr_in6);
//addrlen:地址信息长度,防止访问越界;
eg:
struct sockaddr_in addr;
addr.sin_family = AF_INET;//前两个字节代表IPV4地址结构,IPV6为AF_INET6
addr.sin_port = htons(9000);//端口信息,需要转化为网络字节序
addr.sin_addr.s_addr = inet_addr("192.168.2.2");//本机有的IP地址,inet_addr可将点分十进制转化为长整型数字
bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
ソケットを閉じる
int close(int sockfd);
//实际情况下在TCP通信中,监听套接字基本不关闭,一般只关闭通信套接字
UDP送信データ
ssize_t sendto(int sockfd,char* data,int data_len,int flag,struct socket* dest_addr,socket_t addr_len);
//sockfd:套接字描述符
//data:要发送的数据首地址
//data_len:要发送的数据长度
//flag:选项标志,默认为0----表示当前操作是阻塞操作
//dest_addr:对端地址信息
//addr_len:地址信息结构长度
//返回值:成功返回实际发送数据长度,失败返回-1
UDP受信データ
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flag,struct socket* src_addr,socket_t *addrlen);
//sockfd:套接字描述符
//buf:一块空间首地址,用于存放从内核获取到的数据
//len:要获取的数据长度
//flag:选项标志,默认为0----表示当前操作是阻塞操作
//src_addr:源端地址信息
//*addrlen:这是输入输出型参数,指定想要多长地址,返回实际长度地址
TCP クライアントがサーバーへの接続を開始します。
int connect(int socket, struct sockaddr* srvaddr, socklen_t addrlen);
//srvaddr:服务器地址信息
//返回值:成功返回0,失败返回-1;
TCP サーバーはクライアントによって送信された接続をリッスンします (パラメーターが要求されます)。
int listen(int socket, int backlog);
//backlog:同一时间最大并发连接数,当socket连接队列被放满之后,如果有新的连接请求到来则丢弃,以此限制同一时间所处理的新建连接请求数量;
//该操作将服务器端状态置为listen;
TCPは新しい接続を取得します
接続が完了したカーネルのソケットキューから接続済みのソケット t を取り出し、ディスクリプタを返す。
int accept(int listen_socket, struct sockaddr* addr, socklen_t *addrlen);
//listen_socket:监听套接字,决定了获取的是哪个套接字的新建连接;
//addr:一个地址结构的空间首地址,用于接收新连接的客户端地址信息;
//*addr:用于指定想要获取的地址长度以及返回的实际长度;
//返回值:成功返回新建连接的描述符,失败返回-1;
TCPはデータを送信します
ssize_t send(int sockfd, char *buf, int len, int flag);
//sockfd:新建套接字描述符;
//data:要发送的数据的空间首地址;
//len:要发送的数据长度;
//flag:0,默认阻塞接收;
//返回值:成功返回实际发送的数据长度,出错返回-1,
TCPがデータを受信する
TCP 通信ソケットは、完全な 5 つのタプルを保存します。
ssize_t recv(int sockfd, char *buf, int len, int flag);
//sockfd:新建套接字描述符;
//buf:空间首地址用于存放接收的数据;
//len:要获取的数据长度;
//flag:0,默认阻塞接收;
//返回值:成功返回实际获取到的数据长度,出错返回-1,连接断开返回0;