高校后勤網(wǎng)站建設(shè)要求二級域名和一級域名優(yōu)化難度
文章目錄
- TCP網(wǎng)絡(luò)編程概述
- 1. TCP協(xié)議的特點
- 2. TCP與UDP的差異
- 3. TCP編程流程
- TCP網(wǎng)絡(luò)編程相關(guān)函數(shù)詳解
- 1. `socket()`:創(chuàng)建套接字
- 參數(shù)說明:
- 返回值:
- 示例:
- 2. `connect()`:客戶端連接服務(wù)器
- 參數(shù)說明:
- 返回值:
- 示例:
- 3. `bind()`:服務(wù)器綁定地址和端口
- 參數(shù)說明:
- 返回值:
- 示例:
- 4. `listen()`:監(jiān)聽連接請求
- 參數(shù)說明:
- 返回值:
- 示例:
- 5. `accept()`:接受客戶端連接
- 參數(shù)說明:
- 返回值:
- 示例:
- 6. `send()`:發(fā)送數(shù)據(jù)
- 參數(shù)說明:
- 返回值:
- 示例:
- 7. `recv()`:接收數(shù)據(jù)
- 參數(shù)說明:
- 返回值:
- 示例:
- 8. `close()`:關(guān)閉連接
- 參數(shù)說明:
- 返回值:
- 示例:
- TCP客戶端與服務(wù)端的實現(xiàn)案例
- TCP客戶端實現(xiàn)
- TCP服務(wù)器實現(xiàn)
TCP網(wǎng)絡(luò)編程概述
TCP(Transmission Control Protocol,傳輸控制協(xié)議)是一種面向連接的傳輸層協(xié)議,廣泛應(yīng)用于網(wǎng)絡(luò)通信。與UDP(User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議)不同,TCP提供了可靠的數(shù)據(jù)傳輸機制,確保數(shù)據(jù)能夠完整、有序地從發(fā)送端傳輸?shù)浇邮斩?。本文將詳?xì)介紹TCP協(xié)議的特點、TCP與UDP的差異、TCP編程流程以及客戶端和服務(wù)器的實現(xiàn)方式。
1. TCP協(xié)議的特點
TCP具有以下主要特點:
- 面向連接:在通信前,TCP必須先建立連接。
- 有序號和確認(rèn)機制:每個數(shù)據(jù)包都帶有序號,接收方需要發(fā)送確認(rèn)序號,確保數(shù)據(jù)有序接收。
- 排序、檢錯和失敗重傳:TCP對接收到的數(shù)據(jù)進行排序,檢查數(shù)據(jù)的完整性,如有錯誤,會進行重傳。
- 大文件傳輸:由于TCP能夠分片并重新組裝數(shù)據(jù)包,它特別適合大文件的可靠傳輸。
- 不支持廣播和多播:與UDP不同,TCP不支持廣播和多播,只支持點對點通信。
在TCP通信中,客戶端和服務(wù)器的角色各不相同:
- TCP客戶端:主動向服務(wù)器發(fā)起連接。
- TCP服務(wù)器:被動等待客戶端連接。
2. TCP與UDP的差異
特點 | TCP | UDP |
---|---|---|
面向連接 | 是 | 否 |
可靠傳輸 | 是 | 否 |
順序保證 | 是 | 否 |
傳輸效率 | 較低(需要連接、確認(rèn)等) | 較高(無連接、無確認(rèn)) |
數(shù)據(jù)傳輸大小限制 | 無 | 有(單個數(shù)據(jù)包有限制) |
廣播/多播支持 | 否 | 是 |
TCP更適合需要可靠傳輸?shù)膽?yīng)用場景,如文件傳輸、郵件等,而UDP更適合實時性要求高的應(yīng)用,如視頻、語音傳輸。
3. TCP編程流程
編寫TCP程序時,主要流程如下:
- 創(chuàng)建套接字:使用
socket()
函數(shù)創(chuàng)建TCP套接字。 - 連接服務(wù)器(客戶端)或綁定端口并監(jiān)聽連接(服務(wù)器)。
- 發(fā)送或接收數(shù)據(jù):通過
send()
和recv()
函數(shù)進行數(shù)據(jù)交換。 - 關(guān)閉連接:使用
close()
函數(shù)關(guān)閉套接字。
TCP網(wǎng)絡(luò)編程相關(guān)函數(shù)詳解
在編寫TCP程序時,通常會使用一系列網(wǎng)絡(luò)函數(shù)來創(chuàng)建套接字、建立連接、發(fā)送/接收數(shù)據(jù)并關(guān)閉連接。下面將對TCP網(wǎng)絡(luò)編程中常用的函數(shù)進行詳細(xì)講解,以幫助讀者更好地理解每個函數(shù)的用途及其使用方法。
1. socket()
:創(chuàng)建套接字
socket()
函數(shù)是網(wǎng)絡(luò)編程的基礎(chǔ),用于創(chuàng)建套接字(Socket)。套接字是網(wǎng)絡(luò)通信的端點,類似于兩臺設(shè)備之間的通信通道。它的定義如下:
int socket(int domain, int type, int protocol);
參數(shù)說明:
domain
:指定通信使用的地址族,常用的有:AF_INET
:IPv4網(wǎng)絡(luò)協(xié)議。AF_INET6
:IPv6網(wǎng)絡(luò)協(xié)議。
type
:指定套接字類型,常用的有:SOCK_STREAM
:流式套接字,用于TCP連接。SOCK_DGRAM
:數(shù)據(jù)報套接字,用于UDP連接。
protocol
:一般為0,表示使用默認(rèn)協(xié)議(TCP或UDP)。
返回值:
- 成功:返回套接字的文件描述符。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
int sock = socket(AF_INET, SOCK_STREAM, 0); // 創(chuàng)建TCP套接字
if (sock < 0) {perror("socket creation failed");
}
2. connect()
:客戶端連接服務(wù)器
connect()
函數(shù)用于客戶端主動向服務(wù)器發(fā)起連接請求。在TCP連接中,客戶端通過該函數(shù)連接指定的服務(wù)器。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數(shù)說明:
sockfd
:客戶端套接字描述符。addr
:服務(wù)器的地址結(jié)構(gòu),通常為struct sockaddr_in
。addrlen
:地址結(jié)構(gòu)的大小。
返回值:
- 成功:返回0。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8000); // 服務(wù)器端口號
server_addr.sin_addr.s_addr = inet_addr("10.35.184.221"); // 服務(wù)器IP地址if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {perror("connect failed");
}
3. bind()
:服務(wù)器綁定地址和端口
bind()
函數(shù)用于將套接字綁定到指定的IP地址和端口號。服務(wù)器需要通過bind()
來指定其服務(wù)的地址和端口。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數(shù)說明:
sockfd
:服務(wù)器套接字描述符。addr
:服務(wù)器地址結(jié)構(gòu),通常為struct sockaddr_in
。addrlen
:地址結(jié)構(gòu)的大小。
返回值:
- 成功:返回0。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9000); // 綁定端口9000
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 綁定本機所有IPif (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {perror("bind failed");
}
4. listen()
:監(jiān)聽連接請求
服務(wù)器通過listen()
函數(shù)來監(jiān)聽客戶端的連接請求,進入監(jiān)聽狀態(tài),準(zhǔn)備接受客戶端的連接。
int listen(int sockfd, int backlog);
參數(shù)說明:
sockfd
:服務(wù)器套接字描述符。backlog
:連接隊列的大小,表示服務(wù)器可以處理的等待連接的客戶端數(shù)量。
返回值:
- 成功:返回0。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
if (listen(sock, 5) != 0) { // 最大連接等待隊列長度為5perror("listen failed");
}
5. accept()
:接受客戶端連接
accept()
函數(shù)用于服務(wù)器從連接隊列中取出一個客戶端連接,生成一個新的套接字,用于和該客戶端進行通信。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
參數(shù)說明:
sockfd
:服務(wù)器監(jiān)聽套接字。addr
:客戶端地址結(jié)構(gòu),用于存儲連接的客戶端信息。addrlen
:地址結(jié)構(gòu)的大小。
返回值:
- 成功:返回一個新的已連接套接字描述符,用于與客戶端通信。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sock = accept(sock, (struct sockaddr *)&client_addr, &client_len);
if (client_sock < 0) {perror("accept failed");
}
6. send()
:發(fā)送數(shù)據(jù)
send()
函數(shù)用于向指定的套接字發(fā)送數(shù)據(jù)。
ssize_t send(int sockfd, const void *buffer, size_t length, int flags);
參數(shù)說明:
sockfd
:套接字描述符。buffer
:指向需要發(fā)送數(shù)據(jù)的緩沖區(qū)。length
:要發(fā)送的數(shù)據(jù)長度。flags
:通常為0,可選其他標(biāo)志位。
返回值:
- 成功:返回發(fā)送的字節(jié)數(shù)。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
char message[] = "Hello, TCP Server!";
if (send(sock, message, strlen(message), 0) < 0) {perror("send failed");
}
7. recv()
:接收數(shù)據(jù)
recv()
函數(shù)用于從指定的套接字接收數(shù)據(jù)。
ssize_t recv(int sockfd, void *buffer, size_t length, int flags);
參數(shù)說明:
sockfd
:套接字描述符。buffer
:指向接收數(shù)據(jù)的緩沖區(qū)。length
:緩沖區(qū)大小。flags
:通常為0,可選其他標(biāo)志位。
返回值:
- 成功:返回接收到的字節(jié)數(shù)。
- 失敗:返回-1,并設(shè)置
errno
。 - 如果連接被關(guān)閉,返回0。
示例:
char buffer[128];
ssize_t bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {buffer[bytes_received] = '\0'; // 確保數(shù)據(jù)是以字符串形式輸出printf("Received data: %s\n", buffer);
} else if (bytes_received == 0) {printf("Connection closed by peer\n");
} else {perror("recv failed");
}
8. close()
:關(guān)閉連接
close()
函數(shù)用于關(guān)閉指定的套接字,釋放相關(guān)資源。
int close(int sockfd);
參數(shù)說明:
sockfd
:需要關(guān)閉的套接字描述符。
返回值:
- 成功:返回0。
- 失敗:返回-1,并設(shè)置
errno
。
示例:
close(sock); // 關(guān)閉套接字
TCP客戶端與服務(wù)端的實現(xiàn)案例
TCP客戶端實現(xiàn)
在TCP客戶端編程中,客戶端主動發(fā)起與服務(wù)器的連接。以下是一個基本的TCP客戶端代碼示例:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>typedef struct sockaddr_in addr_in;
typedef struct sockaddr addr;int main(int argc, char const *argv[]) {// 創(chuàng)建TCP套接字int sock = socket(AF_INET, SOCK_STREAM, 0);// 連接TCP服務(wù)器addr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8000);server_addr.sin_addr.s_addr = inet_addr("10.35.184.221");if (connect(sock, (addr *)&server_addr, sizeof(server_addr)) != 0) {perror("connect");return -1;}printf("TCP server connect OK\n");// 每2秒發(fā)送一次數(shù)據(jù)int n = 0;while (1) {char data[] = "hi, tcp server!";if (send(sock, data, strlen(data), 0) > 0) {printf("(%d)發(fā)送成功!\n", ++n);}sleep(2);}close(sock);return 0;
}
TCP服務(wù)器實現(xiàn)
TCP服務(wù)器是被動的,等待客戶端連接。在實現(xiàn)中,服務(wù)器需要首先綁定地址并監(jiān)聽客戶端連接,接著通過accept()
函數(shù)接受客戶端的連接。以下是一個簡單的單聊TCP服務(wù)器實現(xiàn):
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>typedef struct sockaddr_in addr_in;
typedef struct sockaddr addr;typedef struct {int sock;char ip[INET_ADDRSTRLEN];
} client_info;void *readTask(void *arg) {client_info *info = (client_info *)arg;while (1) {char buf[128] = "";ssize_t len = recv(info->sock, buf, 128, 0);if (len > 0) {printf("%s: %s\n", info->ip, buf);}}
}void *sendTask(void *arg) {client_info *info = (client_info *)arg;while (1) {char buf[128] = "";fgets(buf, 128, stdin);buf[strlen(buf)-1] = 0;send(info->sock, buf, strlen(buf), 0);if (strncmp(buf, "bye", 3) == 0) break;}
}int main(int argc, char const *argv[]) {if (argc != 2) return -1;// 創(chuàng)建TCP套接字int sock = socket(AF_INET, SOCK_STREAM, 0);// 設(shè)置服務(wù)器地址addr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[1]));server_addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sock, (addr *)&server_addr, sizeof(server_addr)) != 0) {perror("bind");return -1;}listen(sock, 1000);printf("TCP server running\n");addr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);int client_sock = accept(sock, (addr *)&client_addr, &client_addr_len);if (client_sock > 0) {client_info info;info.sock = client_sock;inet_ntop(AF_INET, &client_addr.sin_addr, info.ip, INET_ADDRSTRLEN);printf("Client connected: %s\n", info.ip);pthread_t read_tid, send_tid;pthread_create(&read_tid, NULL, readTask, &info);pthread_create(&send_tid, NULL, sendTask, &info);pthread_join(send_tid, NULL);}close(sock);return 0;
}
通過上述TCP網(wǎng)絡(luò)編程的介紹和實例代碼,讀者可以掌握如何使用TCP協(xié)議進行可靠的數(shù)據(jù)通信,并根據(jù)實際需求實現(xiàn)功能豐富的網(wǎng)絡(luò)應(yīng)用程序。