ソケットソケット(TCP、UDP)の詳しい説明
LInux を学習する場合、ネットワーク プログラミング ソケットは基礎であり、初心者にとっては学習の難しい点です。この記事を通じて、読者は図と著者のコードを通じて IP アドレス、ポート番号、TCP、UDP の概念、ソケット API を完全に理解できます。実装のアイデア、使用法、クライアント/サーバー通信のシミュレートなど
- マーク: ブログのコード実装を読むのに 18 分かかりました
article 重要なポイント:
- #IP アドレス、ポート番号...
- ソケット API
- UDP クライアントの実装 クライアント/サーバー
- ソケットは、ネットワーク プログラミングにおける通信メカニズムであり、TCP/IP をサポートするネットワーク通信の基本操作単位です。これは、異なるホスト上のプロセス間の双方向通信のためのエンドポイントです。簡単に言うと、通信する 2 つの当事者間の合意です。ソケット内の関連する関数は、通信プロセスを完了するために使用されます。
1、管道(包括无名管道和命名管道); 2、消息队列; 3、信号量; 4、共享存储。 5、……( Socket和Streams支持不同主机上的两个进程IPC)。
通信中、IP は送信元 IP と宛先 IP に分けられます 速達の送信の比較: ネットワーク通信は速達の送信と受信に相当します IP は受信者/送信者のアドレスです。アドレスがわかれば十分です。だけでは不十分です。送信者が誰であるかを知る必要もあります。誰ですか?これはネットワークのポート番号の概念と比較され、ポート番号はプロセスを識別し、分析のために現在のデータがどのプログラムに渡されるかをオペレーティング システムに伝えます。
ポート番号: ポート番号 (ポート) は、トランスポート層プロトコルの内容です。
- ポート番号は 2 バイトの 16 ビット整数です。
- ポート番号は、プロセスを識別し、動作しているプロセスを通知するために使用されます。現在のどのプログラムにデータを分析のために引き渡す必要があるか、 #IP アドレスとポート番号により、ネットワーク上の特定のホストの特定のプロセスを識別できます。
# #ポート番号は 1 つのプロセスによってのみ占有できます。
ポート番号とプロセス:
コンセプト
- プロセスには独自のpid 識別、ポート番号でプロセスを識別することもできます。
送信元ポート番号と宛先ポート番号
- トランスポート層プロトコル (TCP/IP) のデータ セグメント送信元ポート番号と宛先ポート番号と呼ばれる 2 つのポート番号は、「データが誰のものか? 誰に送信されるか?」を表します。
TCP: (TCP ) 送信制御プロトコル、接続指向。これは、信頼性の高いデータ送信を提供する一般的なプロトコルです。#トランスポート層プロトコル
- 接続済み
- 信頼性の高い伝送 #バイト ストリーム指向
- UDP:
(UDP) ユーザー データグラム プロトコルは、コネクションレス指向のプロトコルです。このプロトコルを使用する場合、2 つのアプリケーションが最初に接続を確立する必要はありません。 UDP プロトコルにはエラー回復機能がなく、データの再送信もできないため、このプロトコルのデータ送信セキュリティは不十分です。
- 信頼性の低い伝送
- データグラム指向
- ネットワークバイトオーダー:
# 定義方法ネットワークデータフローのアドレス?
- 実は、この問題は、C 言語のビッグ エンディアンとスモール エンディアンの問題であり、非常に理解しやすいです。
#受信ホストはメモリ アドレスの低位から高位の順に保存します;
-
TCP/IP 規制: ネットワーク データ フローではビッグ エンディアン バイト オーダー、つまり
アドレス上位バイト ; - ホストがビッグ エンディアン マシンであってもリトル エンディアン マシンであっても、TCP/IP 規則に従う必要があります;
送信側がリトル エンディアンの場合は、データを送信する前にビッグエンディアンに変換します。
socket API:
//创建socket文件描述符 (TCP/UDP,客户端+服务器) int socket(int domain, int type, int protocol);
参数1(domain): 选择创建的套接字所用的协议族; <br/> AF_INET : IPv4协议; <br/> AF_INET6: IPv6协议; <br/> AF_LOCAL: Unix域协议; <br/> AF_ROUTE:路由套接口; <br/> AF_KEY :密钥套接口。 <br/>参数2(type):指定套接口类型,所选类型有: <br/> SOCK_STREAM:字节流套接字; <br/> SOCK_DGRAM : 数据报套接字; <br/> SOCK_RAW : 原始套接口。 <br/> procotol: 使用的特定协议,一般使用默认协议(NULL)。
//绑定端口号 (TCP/IP,服务器) int bind(int socket, const struct sockaddr *address, socklen_t address_len);
参数1(socket) : 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。 <br/>参数2(address):指向特定协议的地址指针。 <br/>参数3(address_len):上面地址结构的长度。 <br/>返回值:没有错误,bind()返回0,否则SOCKET_ERROR。
//开始监听socket (TCP,服务器) int listen(int socket, int backlog);
参数1(sockfd):是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。 <br/>参数2(backlog):所监听的端口队列大小。
//接受请求 (TCP,服务器) int accept(int socket, struct sockaddr* address, socklen_t* address_len);
参数1(socket) : 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。 <br/>参数2(address):指向特定协议的地址指针。 <br/>参数3(addrlen):上面地址结构的长度。 <br/>返回值:没有错误,bind()返回0,否则SOCKET_ERROR。
//建立连接 (TCP,客户端) int connect(int sockfd, const struct struct sockaddr *addr, aocklen_t addrlen);
//关闭套接字 int close(int fd);
参数(fd):是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4,IPv6,……
简单的TCP网络程序:
- TCP客户—服务器程序的执行流程图:
服务器代码:
#include<iostream> #include<unistd.h> #include<stdio.h> #include<string.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> using namespace std; #define SERVER_PORT 5050 //端口号 #define SERVER_IP "192.168.3.254" //服务器ip #define QUEUE_SIZE 5 //所监听端口队列大小 int main(int argc, char *argv[]) { //创建一个套接字,并检测是否创建成功 int sockSer; sockSer = socket(AF_INET, SOCK_STREAM, 0); if(sockSer == -1){ perror("socket"); } //设置端口可以重用,可以多个客户端连接同一个端口,并检测是否设置成功 int yes = 1; if(setsockopt(sockSer, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){ perror("setsockopt"); } struct sockaddr_in addrSer,addrCli; //创建一个记录地址信息的结构体 addrSer.sin_family = AF_INET; //所使用AF_INET协议族 addrSer.sin_port = htons(SERVER_PORT); //设置地址结构体中的端口号 addrSer.sin_addr.s_addr = inet_addr(SERVER_IP); //设置其中的服务器ip //将套接字地址与所创建的套接字号联系起来。并检测是否绑定成功 socklen_t addrlen = sizeof(struct sockaddr); int res = bind(sockSer,(struct sockaddr*)&addrSer, addrlen); if(res == -1) perror("bind"); listen(sockSer, QUEUE_SIZE); //监听端口队列是否由连接请求,如果有就将该端口设置位可连接状态,等待服务器接收连接 printf("Server Wait Client Accept......\n"); //如果监听到有连接请求接受连接请求。并检测是否连接成功,成功返回0,否则返回-1 int sockConn = accept(sockSer, (struct sockaddr*)&addrCli, &addrlen); if(sockConn == -1) perror("accept"); else { printf("Server Accept Client OK.\n"); printf("Client IP:> %s\n", inet_ntoa(addrCli.sin_addr)); printf("Client Port:> %d\n",ntohs(addrCli.sin_port)); } char sendbuf[256]; //申请一个发送缓存区 char recvbuf[256]; //申请一个接收缓存区 while(1) { printf("Ser:>"); scanf("%s",sendbuf); if(strncmp(sendbuf,"quit",4) == 0) //如果所要发送的数据为"quit",则直接退出。 break; send(sockConn, sendbuf, strlen(sendbuf)+1, 0); //发送数据 recv(sockConn, recvbuf, 256, 0); //接收客户端发送的数据 printf("Cli:> %s\n",recvbuf); } close(sockSer); //关闭套接字 return 0; }
客户端代码:
#include<iostream> #include<unistd.h> #include<stdio.h> #include<string.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> using namespace std; #define SERVER_PORT 5050 #define SERVER_IP "192.168.3.254" int main(int argc, char *argv[]) { //创建客户端套接字号,并检测是否创建成功 int sockCli; sockCli = socket(AF_INET, SOCK_STREAM, 0); if(sockCli == -1) perror("socket"); //创建一个地址信息结构体,并对其内容进行设置 struct sockaddr_in addrSer; addrSer.sin_family = AF_INET; //使用AF_INET协议族 addrSer.sin_port = htons(SERVER_PORT); //设置端口号 addrSer.sin_addr.s_addr = inet_addr(SERVER_IP); //设置服务器ip bind(sockCli,(struct sockaddr*)&addrCli, sizeof(struct sockaddr)); //将套接字地址与所创建的套接字号联系起来 //创建一个与服务器的连接,并检测连接是否成功 socklen_t addrlen = sizeof(struct sockaddr); int res = connect(sockCli,(struct sockaddr*)&addrSer, addrlen); if(res == -1) perror("connect"); else printf("Client Connect Server OK.\n"); char sendbuf[256]; //申请一个发送数据缓存区 char recvbuf[256]; //申请一个接收数据缓存区 while(1) { recv(sockCli, recvbuf, 256, 0); //接收来自服务器的数据 printf("Ser:> %s\n",recvbuf); printf("Cli:>"); scanf("%s",sendbuf); if(strncmp(sendbuf,"quit", 4) == 0) //如果客户端发送的数据为"quit",则退出。 break; send(sockCli, sendbuf, strlen(sendbuf)+1, 0); //发送数据 } close(sockCli); //关闭套接字 return 0; }
简单的UDP网络程序:
- 相对与TCP来说,UDP安全性差,面向无链接。所以UDP地实现少了连接与接收连接的操作。所以在收发数据时就不能再用send()和recvfrom()了,而是用sendto()和recvto()之名从哪收发数据。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数1(sockfd):是由socket()调用返回的并且未作连接的套接字描述符(套接字号) <br/>参数2(buf):指向存有发送数据的缓冲区的指针 <br/>参数3(len):缓冲区长度。 <br/> **参数4(flags):**flags的值或为0,或为其他
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
参数1(sockfd):是由socket()调用返回的并且未作连接的套接字描述符(套接字号) <br/>参数2(buf):指向存有接收数据的缓冲区的指针 <br/>参数3(len):缓冲区长度 <br/> **参数4(flags):**flags的值或为0,或为其他
服务器端代码:
#include<stdio.h> #include<unistd.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #include<sys/socket.h> int main() { //创建一个套接字,并检测是否创建成功 int sockSer = socket(AF_INET, SOCK_DGRAM, 0); if(sockSer == -1) perror("socket"); struct sockaddr_in addrSer; //创建一个记录地址信息的结构体 addrSer.sin_family = AF_INET; //使用AF_INET协议族 addrSer.sin_port = htons(5050); //设置地址结构体中的端口号 addrSer.sin_addr.s_addr = inet_addr("192.168.3.169"); //设置通信ip //将套接字地址与所创建的套接字号联系起来,并检测是否绑定成功 socklen_t addrlen = sizeof(struct sockaddr); int res = bind(sockSer,(struct sockaddr*)&addrSer, addrlen); if(res == -1) perror("bind"); char sendbuf[256]; //申请一个发送数据缓存区 char recvbuf[256]; //申请一个接收数据缓存区 struct sockaddr_in addrCli; while(1) { recvfrom(sockSer,recvbuf,256,0,(struct sockaddr*)&addrCli, &addrlen); //从指定地址接收客户端数据 printf("Cli:>%s\n",recvbuf); printf("Ser:>"); scanf("%s",sendbuf); sendto(sockSer,sendbuf,strlen(sendbuf)+1,0,(struct sockaddr*)&addrCli, addrlen); //向客户端发送数据 } return 0; }
客户端代码:
#include<stdio.h> #include<unistd.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #include<sys/socket.h> int main() { //创建一个套接字,并检测是否创建成功 int sockCli = socket(AF_INET, SOCK_DGRAM, 0); if(sockCli == -1){ perror("socket"); } addrSer.sin_family = AF_INET; //使用AF_INET协议族 addrSer.sin_port = htons(5050); //设置地址结构体中的端口号 addrSer.sin_addr.s_addr = inet_addr("192.168.3.169"); //设置通信ip socklen_t addrlen = sizeof(struct sockaddr); char sendbuf[256]; //申请一个发送数据缓存区 char recvbuf[256]; //申请一个接收数据缓存区 while(1){ //向客户端发送数据 printf("Cli:>"); scanf("%s",sendbuf); sendto(sockCli, sendbuf, strlen(sendbuf)+1, 0, (struct sockaddr*)&addrSer, addrlen); 接收来自客户端的数据 recvfrom(sockCli, recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&addrSer, &addrlen); printf("Ser:>%s\n", recvbuf); } return 0; }
<br/>
【推荐课程:TCP/IP视频教程】
以上がソケットソケット(TCP、UDP)の詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









PHP および UDP プロトコルを使用して非同期通信を実装する方法 最新のインターネット アプリケーションでは、非同期通信は非常に重要な方法となっています。非同期通信を使用すると、メインスレッドをブロックすることなくユーザーリクエストを同時に処理できるため、システムのパフォーマンスと応答速度が向上します。人気のバックエンド プログラミング言語である PHP は、UDP プロトコルを使用して非同期通信を実現する方法を教えてください。この記事では、PHP で UDP プロトコルを使用して簡単な非同期通信を実装する方法を、具体的なコード例を添付して紹介します。 1. UDP プロトコルの概要 U

この記事では、php+socket に関する関連知識を提供します。主に IO 多重化と php+socket が Web サーバーを実装する方法を紹介します。興味のある方は以下をご覧ください。皆様のお役に立てれば幸いです。

一般的な UDP ポート番号は 53、69、161、2049、68、および 520 です。 UDP はポート番号を使用して、さまざまなアプリケーション用に独自のデータ送信チャネルを予約します: 1. ネットワーク ファイル システム (NFS)、ポート番号は 2049、2. 簡易ネットワーク管理プロトコル (SNMP)、ポート番号は 161、3. ドメイン名システム (DNS)、ポート番号は 53、4. 簡易ファイル転送システム (TFTP)、ポート番号は 69、5. 動的ホスト構成プロトコル (DHCP)、ポート番号は 68、6. ルーティング情報プロトコル、ポート番号は 520 などです。

win10でtcp/ipプロトコルをリセットするにはどうすればよいですか?実際、その方法は非常に簡単で、ユーザーがコマンド プロンプトに直接入力し、ctrl Shift Enter キーの組み合わせを押して操作を実行するか、reset コマンドを直接実行して設定することができます。 Windows 10 で TCP/IP プロトコル スタックをリセットする方法をユーザーに注意深く紹介します。 Windows 10 で tcp/ip プロトコル スタックをリセットする方法 1。 管理者権限 1. ショートカット キー win R を使用してファイル名を指定して実行ウィンドウを直接開き、「cmd」と入力し、ctrl Shift Enter キーの組み合わせを押し続けます。 2. または、スタート メニューでコマンド プロンプトを直接検索し、右クリックします。

1. TCP プロトコルに基づくソケット プログラミング 1. ソケット ワークフローはサーバー側から始まります。サーバーはまずソケットを初期化し、次にポートにバインドし、ポートをリッスンし、accept を呼び出してブロックし、クライアントが接続するのを待ちます。このとき、クライアントがSocketを初期化してからサーバーに接続(connect)すると、接続に成功するとクライアントとサーバー間の接続が確立されます。クライアントがデータ リクエストを送信し、サーバーがリクエストを受信して処理し、次に応答データをクライアントに送信し、クライアントがデータを読み取り、最後に接続を閉じます。インタラクションは終了します。インタラクションを実装するには、次の Python コードを使用します。 :インポートソ

TCP クライアント TCP プロトコルを使用して継続的な対話を実現するクライアントのサンプル コード: importsocket#クライアント設定 HOST='localhost'PORT=12345#TCP ソケットを作成し、サーバーに接続 client_socket=socket.socket(socket.AF_INET,socket . SOCK_STREAM)client_socket.connect((HOST,PORT))whileTrue:#ユーザー入力を取得 message=input("送信するメッセージを入力してください:&

ここで言う「コネクション指向」とは、コネクションを確立し、コネクションを利用し、コネクションを解放する必要があることを意味します。接続の確立とは、よく知られている TCP スリーウェイ ハンドシェイクを指します。接続を使用する場合、データは 1 回の送信と 1 回の確認の形式で送信されます。また、一般的な TCP 4 波である接続の解放もあります。

SpringBoot 側の最初のステップは依存関係を導入することです。まず、WebSocket に必要な依存関係と、出力形式 com.alibabafastjson1.2.73org.springframework.bootspring-boot-starter-websocket を処理するための依存関係を導入する必要があります。 2 番目のステップは、WebSocket 構成クラス importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Config を作成することです。
