TCPは、TCP / IPプロトコルスイートである信頼性の高い接続指向のプロトコルのワークフロー方法は、本明細書に説明されるとLinuxでプログラムすることが、。
TCPの基礎
TCPは、近隣の高層にサービスを提供します。TCP層は、他のアプリケーションへのデータ転送アプリケーションからTCPデータ転送を達成するために、このように、アプリケーション層であり、。
データを提供するために、TCPのプログラミングおよびサービスを使用して、TCPアプリケーションの呼び出しは、受信したデータアプリケーションの宛先アドレスとポート番号を区別するために使用され、送信する準備ができています。
通常、アプリケーションは、他のソケットにTCPソケット、TCPデータ転送管理を開いて、サービスを利用します。
一意のIP送信元/送信先を介してネットワークに接続された2つのデバイスを区別することができ、ネットワーク接続を一意ソケット・アプリケーションのソース/デスティネーションで2分割することができます。
3回によって初期化TCPセッションハンドシェイク。
目的は、他のホストに伝え、データセグメント同期を送受信する3ウェイハンドシェイクは、時間のデータ量を受信することができ、および仮想接続を確立するようにすることです。
スリーウェイハンドシェイクは、簡単なプロセスであります:
- 初期マスター同期フラグは、セッション要求を送信したデータセグメントによって設定されています。
- バックに応答して発現項目送信することによって、ホストを有するデータセグメントを受信した:同期フラグはセット、ゆうデータセグメントの部分、および受信されたデータセグメントの次のバイトのシーケンス番号で応答を送信する開始シーケンス番号です。
- 要求元ホストがデータ復帰期間を送信し、確認応答シーケンス番号と確認応答番号を教えます。
TCP 3ウェイハンドシェイク手順の概略
基本的なTCPプロトコルエンティティは、送信側がデータグラムを送信する場合、それはタイマーを開始し、スライディングウィンドウのプロトコルを使用しています。データグラムが宛先に到達すると、受信側TCPエンティティは、バックパケットを受信し、次の所望のデータのシーケンス番号を示す肯定応答シーケンス番号を含むデータパケットを送信します。メッセージが到着する前に確認応答タイマーの送信者が満了する場合、送信者は、パケットを再送します。
TCPヘッダフォーマット
その種々の部分を次のように
- 源端口,目的端口:16位长,标识出远端和本地的端口号。
- 序号:32位长,标识发送数据报的顺序。
- 确认号:32位长,希望收到的下一个数据包的序列号,
- TCP头长:4位长,表明 TCP 头中包含多少个 32 位字。
- 6 位未用。
- ACK:ACK位置 1 表明确认号是合法的,如果 ACK 为0,那么教据报不包含确认信息,确认字段被省略。
- PSH:表示是带有 PUSH 标志的数据,接收方只等请求数据包一到便将其送往应用程序而不必等到缓冲区装满时才传送。
- RST:用于复位由于主机崩溃或其他原因而出现的错误连接,还可以用于拒绝非法的数据包或拒绝连接请求。
- SYN:用于建立连接
- FIN:用于释放连接。
- 窗口大小:16位长,窗口大小字段表示在确认了字节之后还可以发送多个字节。
- 校验和:16位长,是为了确保高可靠性而设置的,用于校验头部、数据和伪 TCP 头部之和。
- 可选项:0个或多个32位字,包括最大 TCP 载荷、滑动窗口比例以及选择重发数据包等选项。
TCP 的工作流程
基于 TCP 传输协议的服务器与客户端间的通信工作流程可以利用下图所示的过程来描述。
- 服务器先用 socket 函数来建立一个套接口,用这个套接口完成通信的监听及数据的收发。
- 服务器利用 bind 函数来绑定一个端口号和 IP 地址,使套接口与指定的端口号、IP 地址相关联。
- 服务器调用 listen 函数, 使服务器的这个端口和 IP 处于监听状态,等待网络中某一客户机的连接请求。
- 客户机用 socket 函数建立一个套接口,设定远程 IP 和端口。
- 客户机调用 connect 函数连接远程计算机指定的端口。
- 服务器调用 accept 函数来接收远程计算机的连接请求,建立起与客户机之间的通信连接。
- 建立连接以后,客户机利用 write 函数或 send 函数向 socket 中写入数据,也可以使用 read 函数或 recv 函数读取服务器发送来的数据。
- 服务器利用 read函数或 recv 函数读取客户机发送来的数据,也可以利用 write 函数或 send 函数来发送数据。
- 通信が終了した後、クローズ機能およびソケット接続を使用して。
アプリケーション例
実施例1及び2は、TCPサーバとクライアントの通信を使用してアプリケーションの例である:サーバは、クライアント要求を受信し、子プロセスが作成され、現在のシステム時刻がクライアントに送信され、サーバは、クライアント情報が読み出され、送信します。
[] TCP通信のサーバー側の1ケース
アプリケーションコードは、通信ポートとして25555ポートを使用し、最初のソケット関数呼び出し機能は、ソケットとバインドバインドされたポートを作成し、クライアントからの関数呼び出し接続要求を聞くために、クライアントの接続情報であれば、関数は、接続を受け受け入れ、子プロセスを作成し、子に現在時刻情報を送信し、最終的に近いソケット・インタフェースの子プロセスが終了使用しています。
コードは以下の通りであります:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERV_PORT 25555 //服务器接听端口号
#define BACKLOG 20 //请求队列中允许请求数
#define BUF_SIZE 256 //缓冲区大小
int main(int arge,char *argv[])
{
int ret;
time_t tt;
struct tm *ttm;
char buf[BUF_SIZE];
pid_t pid; //定义管道描述符
int sockfd;//定义 sock 描述符
int clientfd; //定义数据传输 sock 描述符
struct sockaddr_in host _addr;//本机IP地址和端口信息
struct sockaddr_in client_addr;//客户端IP地址和端口信息
int length = sizeof client_addr;
//创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);//TCP/IP协议,数据流套接字
if(sockfd == -1)//判断socket函数的返回值
{
printf("创建socket失败!\n");
return 0;
}
//绑定套接字
bzero(&host_addr, sizeof host_addr);
host_addr.sin_family = AF_INET;//TCP/IP协议
host_addr.sin_port = htons(SERV_PORT);//设定端口号
host_addr.sin_addr.s_addr = INADDR_ANY;//本地IP地址
ret = bind(sockfd, (struct sockaddr *)&host_addr, sizeof host_addr); //绑定套接字
if(ret == -1) //判断bind函数的返回值
{
printf("调用bind失败!\n");
return 1;
}
//监听网络端口
ret = listen(sockfd, BACKLOG);
if(ret==-1)//判断listen函数的返回值
{
printf("调用listen函数失败.\n");
return 1;
}
while(1)
{
clientfd = accept(sockfd,(struct sockaddr*)&client_addr, &length);//接收连接请求
if(clientfd = -1)
{
printf("调用accept接受连接失败.\n");
return 1;
}
pid = fork();//创建子进程
if(pid == 0)//在子进程中处理
{
while(1)
{
bzero(buf, sizeof buf);//首先清空缓冲区
tt = time(NULL);
ttm = localtime(&tt);//获取当前时间参数
strcpy(buf, asctime(ttm));//将时间信息 copy 进缓冲区
send(clientfd, buf, strlen(buf), 0);//发送数据
sleep(2);
}
close(clientfd);//调用close函数关闭连接
else if(pid> 0)
{
close(clientfd);//父进程关闭套接字,准备下一个客户端连接
}
}
return 0;
}
[2例] TCPクライアント通信プログラム
使用のargv [1]は、接続、serv_addr構造体で指定されたアドレスへIPアドレス、および接続機能サーバを使用して接続するためのIPアドレスとして使用後にソケットを作成しますRECVサーバーやプリント出力から送信された時刻情報を受信します。
コードは以下の通りであります:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERV_PORT 25555 //服务器接听端口号
#define BACKLOG 20 //请求队列中允许请求数
#define BUF_SIZE 256 //缓冲区大小
int main(int arge, char *argv[])
{
int ret;
char buf[BUF_SIZEI];
int sockfd; //定义 sock 描述符
struct sockaddr_in serv_addr; //服务器 IP 地址和端口信息
if(argc != 2)
{
print("命令行输入有误.\n");//命令行带IP
returm 1;
}
//创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);//TCP/IP协议,数据流套接字
if(sockfd = -1)
{
printf("调用socket函数失败.\n");
return 2;
}
//建立连接
bzero(&serv_addr, sizeof serv_addr);
serv_addr.sin_family = AF_INET;//TCP/IP协议
serv_addr.sin_port = htons(SERV_PORT);//设定端口号
//serv_ addr sin addr.s_ addr = INADDR ANY;//使用回环地址127.0.0.1
inet_aton(argv[1], (struct sockaddr *)&serv_addr.sin_addr.s_addr);//设定IP地址
ret = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof serv_ addr); //绑定套接子
if(ret==-1)
{
printf("调用connect函数失败.\n");
return 3;
}
while(1)
{
bzero(buf, sizeof buf);
recv(sockfd, buf, sizeof(buf), 0);//接收数据
printf("接收到: %s", buf);
sleep(1);
}
close(sockfd); //关闭链接
return 0;
}
上記の二つの世代のプログラムが実行可能ファイル内の2台の異なる端末である実行、出力時間を見ることができます。