文章目录
- TCP是什么
- 准备工作
- CMakeLists.txt
- 服务端代码
- 客户端代码
- 参考
TCP是什么
TCP(传输控制协议)是一种在计算机网络中广泛使用的协议,它提供了可靠的、面向连接的数据传输服务。TCP 是 OSI 模型中的传输层协议,它确保了数据的可靠性、顺序性和流控制。
以下是 TCP 通讯的一些关键特点和概念:
-
可靠性: TCP 提供可靠的数据传输。它使用确认机制,确保数据的每个部分都已被成功接收,如果数据在传输中出现错误或丢失,TCP 将负责重新传输。
-
面向连接: TCP 是一种面向连接的协议。在进行数据传输之前,必须先建立连接。连接的建立和终止都需要一些握手和挥手的过程,以确保双方都已准备好进行通信。
-
全双工通信: TCP 支持全双工通信,即双方可以同时发送和接收数据。这使得双方能够在同一时间内进行双向的通信。
-
流控制: TCP 使用窗口控制机制来进行流量控制。这确保了在通信双方之间合适的速率上进行数据传输,防止发送方发送过多数据导致接收方无法处理。
-
顺序性: TCP 保证传输的数据按照发送的顺序到达接收端。即使在网络中出现乱序的情况,TCP 会重新排序数据,以确保按照正确的顺序进行处理。
-
连接管理: TCP 提供连接的建立、维护和释放。连接的建立和释放过程中包含握手和挥手的步骤,以确保通信的可靠性和一致性。
-
端口和套接字: 在 TCP 通信中,通信的双方通过端口和套接字进行标识。端口用于标识特定的应用程序,而套接字则表示在网络中的通信端点。
-
可靠的错误检测和重传机制: TCP 使用序号和确认号来确保数据的可靠传输。如果发送方没有收到确认,它将会重新发送数据。
总体而言,TCP 是一种适用于可靠、有序、面向连接的数据传输的协议。它适用于需要确保数据完整性的应用场景,如文件传输、网页浏览、电子邮件等。然而,由于其一些额外的开销和复杂性,对于一些实时性要求较高的应用,可能会选择使用UDP等协议。
准备工作
- 打开防火墙:
sudo ufw enable
- 打开目标端口:例如打开22端口
sudo ufw allow 22
- 测试前,ping一下,看连接是或否成功。
两端的通讯流程
CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(ExampleProgram)
set(CMAKE_CXX_STANDARD 11)
add_executable(tcp-client tcp-client.cpp)
add_executable(tcp-server tcp-server.cpp)
# Add -lpthread
target_link_libraries(tcp-client pthread)
target_link_libraries(tcp-server pthread)
服务端代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
// 创建服务器套接字
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
std::cerr << "Failed to create server socket." << std::endl;
return 1;
}
// 设置服务器地址结构
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080); // 服务器监听的端口号
// 绑定套接字
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
std::cerr << "Bind failed." << std::endl;
close(serverSocket);
return 1;
}
// 监听连接
if (listen(serverSocket, SOMAXCONN) == -1) {
std::cerr << "Listen failed." << std::endl;
close(serverSocket);
return 1;
}
std::cout << "Server is listening for incoming connections..." << std::endl;
while (true) {
// 接受连接
int clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket == -1) {
std::cerr << "Accept failed." << std::endl;
close(serverSocket);
return 1;
}
std::cout << "Connection established with a client." << std::endl;
// 发送消息给客户端
const char* message = "Hello from server!";
if (send(clientSocket, message, strlen(message), 0) == -1) {
std::cerr << "Error sending message." << std::endl;
}
// 关闭客户端套接字
close(clientSocket);
}
// 服务器永远不会执行到这里,但可以加上关闭服务器套接字的代码
close(serverSocket);
return 0;
}
客户端代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
while (true) {
// 创建客户端套接字
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
std::cerr << "Failed to create client socket." << std::endl;
return 1;
}
// 设置服务器地址结构
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("192.168.110.83"); // 服务器的 IP 地址
serverAddr.sin_port = htons(8080); // 服务器监听的端口号
// 连接到服务器
if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
std::cerr << "Connection failed." << std::endl;
close(clientSocket);
return 1;
}
std::cout << "Connected to the server." << std::endl;
// 接收消息
char buffer[256];
memset(buffer, 0, sizeof(buffer));
if (recv(clientSocket, buffer, sizeof(buffer), 0) == -1) {
std::cerr << "Error receiving message." << std::endl;
} else {
std::cout << "Received message from server: " << buffer << std::endl;
}
// 关闭客户端套接字
close(clientSocket);
// 在这里可以添加一些延时,以避免过于频繁地连接服务器
sleep(1);
}
return 0;
}
参考
https://blog.csdn.net/cyj_001/article/details/131782022
https://www.bilibili.com/video/BV1ne411A7hP/?spm_id_from=333.337.search-card.all.click&vd_source=667c3d14dbb51ec849c0bc7c38329d10