目錄
TCP介紹
代碼實現(xiàn)
server(服務(wù)器端)
代碼分析
client(客戶端)
代碼分析
結(jié)果展示
TCP介紹
TCP (Transmission Control Protocol) 是一種面向連接的協(xié)議,用于在計算機(jī)網(wǎng)絡(luò)中傳輸數(shù)據(jù)。TCP 可以確保數(shù)據(jù)的可靠傳輸,即使在網(wǎng)絡(luò)環(huán)境不穩(wěn)定的情況下也能夠保證數(shù)據(jù)的完整性和順序。以下是 TCP 通信的一些特點:
- 面向連接:在 TCP 通信中,通信的雙方必須先建立一個連接,然后才能進(jìn)行數(shù)據(jù)的傳輸。連接的建立需要經(jīng)過三次握手過程,確保雙方都能夠進(jìn)行通信。
- 可靠傳輸:TCP 可以保證數(shù)據(jù)的可靠傳輸,它使用確認(rèn)和重傳機(jī)制來確保數(shù)據(jù)的完整性和順序。每當(dāng)發(fā)送方發(fā)送數(shù)據(jù)包時,接收方都會發(fā)送一個確認(rèn)信息來表示已經(jīng)收到數(shù)據(jù)。如果發(fā)送方?jīng)]有收到確認(rèn)信息,它會重新發(fā)送數(shù)據(jù),直到接收方確認(rèn)為止。
- 流量控制:TCP 可以根據(jù)接收方的處理能力來控制數(shù)據(jù)的發(fā)送速度,防止發(fā)送方發(fā)送過多的數(shù)據(jù)導(dǎo)致接收方無法處理。
- 擁塞控制:TCP 可以根據(jù)網(wǎng)絡(luò)狀況來調(diào)整發(fā)送方的數(shù)據(jù)發(fā)送速度,防止網(wǎng)絡(luò)擁塞導(dǎo)致數(shù)據(jù)丟失和傳輸延遲。
總之,TCP 是一種可靠的協(xié)議,它在網(wǎng)絡(luò)傳輸中發(fā)揮了重要的作用,特別是在需要確保數(shù)據(jù)完整性和順序的場合,如 Web 瀏覽器、電子郵件、文件傳輸?shù)葢?yīng)用中。
代碼實現(xiàn)
server(服務(wù)器端)
/server*****/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
//1.使用socket函數(shù)-創(chuàng)建流式套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //創(chuàng)建IPv4的TCP套接字
if (sockfd < 0)
{
perror("scoket err");
return -1;
}
//socket第一個參數(shù)已經(jīng)是AF_INET ipv4,是用bind函數(shù)得填充ipv4結(jié)構(gòu)體
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //設(shè)置地址族為IPv4
saddr.sin_port = htons(atoi(argv[1])); //端口占了兩個字節(jié),將小端轉(zhuǎn)換為大端
saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); //綁定任意可用的IP地址
//2.綁定套接字,ip和端口
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind");
return -1;
}
else
{
printf("bind ok\n");
}
//3.監(jiān)聽-被動狀態(tài)
if (listen(sockfd, 5) < 0) //設(shè)置監(jiān)聽隊列大小為5
{
perror("listen err");
return -1;
}
//4.阻塞等待客戶端鏈接
int accept_fd = accept(sockfd, NULL, NULL); //接受客戶端的連接請求
if (accept_fd < 0)
{
perror("accept err");
return -1;
}
//5.循環(huán)接受消息
char arr[128];
ssize_t ret;
while (1)
{
ret = recv(accept_fd, arr, sizeof(arr), 0); //從客戶端接收數(shù)據(jù)
if (ret < 0)
{
perror("recv err");
return -1;
}
else if (ret == 0)
{
perror("clien exit");
break;
}
else
{
write(1, arr, ret); //將接收到的數(shù)據(jù)輸出到終端
}
}
close(sockfd); //關(guān)閉套接字
close(accept_fd);
return 0;
}
代碼分析
具體分析如下:
第1行到第15行,定義了程序的主函數(shù)main(),并進(jìn)行了如下操作:
使用socket函數(shù)創(chuàng)建一個IPv4的TCP套接字。
利用bind函數(shù)將套接字綁定到指定IP和端口上。
使用listen函數(shù)將套接字設(shè)置為監(jiān)聽狀態(tài),設(shè)置了監(jiān)聽隊列的長度為5。
使用accept函數(shù)等待客戶端連接請求,并返回連接套接字的文件描述符。
在一個while循環(huán)中循環(huán)接收客戶端發(fā)送的消息,然后將接收到的消息輸出到終端。
關(guān)閉套接字。
第17行到第22行,定義了一個IPv4的套接字地址結(jié)構(gòu)體sockaddr_in,并設(shè)置IP地址和端口號。
第24行到第32行,利用bind函數(shù)將套接字綁定到指定IP和端口上,并檢查綁定是否成功。
第35行到第41行,使用listen函數(shù)將套接字設(shè)置為監(jiān)聽狀態(tài),并設(shè)置監(jiān)聽隊列的長度為5,如果監(jiān)聽失敗則輸出錯誤信息并退出程序。
第44行到第50行,使用accept函數(shù)阻塞等待客戶端連接請求,如果接受失敗則輸出錯誤信息并退出程序,否則返回連接套接字的文件描述符。
第53行到第64行,在一個while循環(huán)中循環(huán)接收客戶端發(fā)送的消息,如果接收失敗則輸出錯誤信息并退出程序,如果接收到的消息長度為0則說明客戶端已經(jīng)關(guān)閉連接,退出循環(huán);否則將接收到的消息輸出到終端。
第67行到第70行,關(guān)閉套接字并退出程序。
該程序?qū)崿F(xiàn)了一個簡單的TCP服務(wù)器,可以接收客戶端的連接并循環(huán)接收客戶端發(fā)送的消息,將接收到的消息輸出到終端。
client(客戶端)
/client**********/
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
//1. 使用socket創(chuàng)建流式套接子
int socket_fd;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0)
{
perror("socket_fd err"); // 打印錯誤信息
return -1;
}
//2. 請求鏈接
struct sockaddr_in cnt;
cnt.sin_family = AF_INET;
cnt.sin_port = htons(atoi(argv[1])); // 將輸入的字符串參數(shù)轉(zhuǎn)換為整數(shù)端口號
cnt.sin_addr.s_addr = inet_addr("0.0.0.0"); // 設(shè)置服務(wù)器的IP地址
if (connect(socket_fd, (struct sockaddr *)&cnt, sizeof(cnt)) < 0)
{
perror("connect err"); // 打印錯誤信息
return -1;
}
char buf[128];
int ch;
while (1)
{
ch = read(0, buf, 128); // 從標(biāo)準(zhǔn)輸入讀取用戶輸入的數(shù)據(jù)
if (send(socket_fd, buf, ch, 0) < 0) // 發(fā)送數(shù)據(jù)到服務(wù)器
{
perror("send err"); // 打印錯誤信息
return -1;
}
}
close(socket_fd); // 關(guān)閉套接字
return 0;
}
代碼分析
這是一個TCP客戶端代碼,它的主要功能是連接到指定的服務(wù)器并發(fā)送數(shù)據(jù)。下面是代碼的逐行分析:
socket_fd = socket(AF_INET, SOCK_STREAM, 0);:創(chuàng)建一個流式套接字。
cnt.sin_family = AF_INET;:設(shè)置服務(wù)器地址的協(xié)議族為IPv4。
cnt.sin_port = htons(atoi(argv[1]));:將從命令行參數(shù)獲取的字符串端口號轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序的整數(shù)端口號,并將其存儲在 sockaddr_in 結(jié)構(gòu)體的 sin_port 字段中。
cnt.sin_addr.s_addr = inet_addr("0.0.0.0");:設(shè)置服務(wù)器IP地址為 0.0.0.0,表示客戶端可以連接到任何一個可用的IP地址。
connect(socket_fd, (struct sockaddr *)&cnt, sizeof(cnt)):連接到服務(wù)器。這個函數(shù)將套接字連接到 sockaddr_in 結(jié)構(gòu)體中描述的IP地址和端口號。如果連接失敗,將返回一個負(fù)數(shù)值。
ch = read(0, buf, 128);:從標(biāo)準(zhǔn)輸入讀取最多128個字節(jié)的數(shù)據(jù),并將其存儲在 buf 中。
send(socket_fd, buf, ch, 0):將讀取的數(shù)據(jù)發(fā)送到服務(wù)器。如果發(fā)送失敗,將返回一個負(fù)數(shù)值。
close(socket_fd);:關(guān)閉套接字。
在主循環(huán)中,該客戶端將不斷地從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)并將其發(fā)送到服務(wù)器,直到程序被強(qiáng)制終止。
結(jié)果展示
文章來源:http://www.zghlxwxcb.cn/news/detail-606623.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-606623.html
到了這里,關(guān)于TCP實現(xiàn)服務(wù)器和客戶端通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!