【Socket通信】TCP

本文详细介绍了TCP通信的基本原理,包括WinTcpSocket的简单实现、TcpClient与TcpServer的代码示例,以及如何通过定时发送心跳消息保持链路活跃,解决码流发送和组包问题,确保数据有序传输。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、TCP通信

1. 简单的winTcpSocket实现

1.1 TcpClient代码实现

// ConsoleApplication21.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>

#pragma  comment(lib,"ws2_32.lib")

//添加此句,屏蔽"warning作为error", 提高兼容性
#pragma warning(disable:4996) 

int main(int argc, char *argv[])
{
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA data;
	if (WSAStartup(sockVersion, &data) != 0)
	{
		return 0;
	}
	SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sclient == INVALID_SOCKET)
	{
		printf("invalid socket !");
		return 0;
	}
	sockaddr_in serAddr;
	serAddr.sin_family = AF_INET;
	serAddr.sin_port = htons(8888);
	serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
	{
		printf("connect error !");
		closesocket(sclient);
		return 0;
	}
	char *sendData = "[TCP][Clietn]Hello TCP Server,i am TCP Client!\n";
	send(sclient, sendData, strlen(sendData), 0);
	char recData[255];
	int ret = recv(sclient, recData, 255, 0);
	if (ret > 0)
	{
		recData[ret] = 0x00;
		printf(recData);
	}
	closesocket(sclient);
	WSACleanup();
	return 0;
}

1.2 TcpServer代码实现

// ConsoleApplication22.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdafx.h"
#include <winsock2.h> 
#include <windows.h>
#include <Ws2tcpip.h>

#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}
	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}
	//绑定IP和端口
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !");
	}
	//开始监听
	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}
	//循环接收数据
	SOCKET sClient;
	sockaddr_in remoteAddr;
	int nAddrlen = sizeof(remoteAddr);
	char revData[255];
	while (true)
	{
		printf("[TCP][Server] Listening waiting...\n");
		sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			printf("accept error !");
			continue;
		}
		printf("[TCP][Server]a client wasaccepted\r\n"); // inet_ntoa(remoteAddr.sin_addr)函数:将网络地址转换成“.”点隔的字符串格式
								 //接收数据
		int ret = recv(sClient, revData, 255, 0);
		if (ret > 0)
		{
			revData[ret] = 0x00;
			printf(revData);
		}
		//发送数据
		char * sendData = "[TCP][Server] hello TCP Client,i am TCP Server !\n";
		send(sClient, sendData, strlen(sendData), 0);
		closesocket(sClient);
	}
	closesocket(slisten);
	WSACleanup();
	return 0;
}

1.3 代码执行结果分析

  1. 先启动服务端,服务端进入监听状态:
    在这里插入图片描述
  2. 启动客户端后,TCP的服务端接收了来自客户端的链接请求后,也收到了来自客户端的数据:
    在这里插入图片描述
  3. 客户端收到了来自服务端的数据
    在这里插入图片描述

2. TcpSocketClient定时发送心跳

#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
 
class TCPClient {
public:
    TCPClient(const std::string& serverIP, int port) : m_serverIP(serverIP), m_port(port) {}
    
    void start() {
        // 创建Socket并连接服务器
        if ((m_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Failed to create socket");
            return;
        }
        
        struct sockaddr_in servAddr{};
        servAddr.sin_family = AF_INET;
        servAddr.sin_port = htons(m_port);
        if (inet_pton(AF_INET, m_serverIP.c_str(), &servAddr.sin_addr) <= 0) {
            perror("Invalid address or address not supported");
            close(m_sockfd);
            return;
        }
        
        if (connect(m_sockfd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr)) < 0) {
            perror("Connection failed");
            close(m_sockfd);
            return;
        }
        
        // 开始定时发送心跳包线程
        m_heartbeatThread = std::thread([this](){ heartbeat(); });
    }
    
private:
    void heartbeat() {
        while (true) {
            // 构造心跳数据包(这里只是一个示例)
            const char* data = "Heartbeat";
            
            // 向服务器发送心跳包
            send(m_sockfd, data, strlen(data), 0);
            
            // 休眠指定时间后再次发送心跳包
            std::this_thread::sleep_for(std::chrono::seconds(5));
        }
    }
    
    std::string m_serverIP;   // 服务器IP地址
    int m_port;               // 服务器端口号
    int m_sockfd;              // Socket文件描述符
    std::thread m_heartbeatThread;  // 定时发送心跳包的线程
};
 
int main() {
    std::string serverIP = "127.0.0.1";  // 设置服务器IP地址
    int port = 8080;                      // 设置服务器端口号
    
    TCPClient client(serverIP, port);
    client.start();
    
    // 等待主线程结束或按Ctrl+C退出
    for (;;) {
        sleep(1);
    }
}





// --------------------------------TCP客户端类:定时5秒发一次向服务端发送一次心跳
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
#include <chrono>
 
class TCPClient {
public:
    TCPClient(const std::string& serverIP, int port) : m_serverIP(serverIP), m_port(port) {}
    
    void start() {
        // 创建Socket
        if ((m_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Failed to create socket");
            return;
        }
        
        // 设置服务器地址信息
        struct sockaddr_in servAddr{};
        servAddr.sin_family = AF_INET;
        servAddr.sin_port = htons(m_port);
        inet_pton(AF_INET, m_serverIP.c_str(), &servAddr.sin_addr);
        
        // 连接到服务器
        if (connect(m_sockfd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr)) == -1) {
            perror("Failed to connect to the server");
            close(m_sockfd);
            return;
        }
        
        // 开始发送心跳消息
        sendHeartbeat();
    }
private:
    void sendHeartbeat() {
        while (true) {
            // 构造心跳消息
            const char heartbeat[] = "heartbeat";
            
            // 发送心跳消息
            ssize_t bytesSent = write(m_sockfd, heartbeat, strlen(heartbeat));
            if (bytesSent == -1) {
                perror("Failed to send heartbeat message");
                break;
            } else if (bytesSent != static_cast<ssize_t>(strlen(heartbeat))) {
                std::cerr << "Partially sent heartbeat message" << std::endl;
            }
            
            // 休眠5秒后再发送下一条心跳消息
            std::this_thread::sleep_for(std::chrono::seconds(5));
        }
    }
    
    std::string m_serverIP;
    int m_port;
    int m_sockfd;
};
 
int main() {
    std::string serverIP = "127.0.0.1";   // 服务器IP地址
    int port = 8080;                       // 服务器监听端口号
    
    TCPClient client(serverIP, port);
    client.start();
    
    return 0;
}








//------------------------C++实现的TCP客户端类,并在其中创建了一个线程来每隔5秒发送一次心跳
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <cstdlib> // for exit() function
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
 
class TCPClient {
private:
    int clientSocket;
public:
    void connectToServer(const std::string& serverIP, const unsigned short port) {
        struct sockaddr_in serverAddress{};
        
        if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Failed to create socket");
            exit(-1);
        }
        
        serverAddress.sin_family = AF_INET;
        serverAddress.sin_port = htons(port);
        
        if (inet_pton(AF_INET, serverIP.c_str(), &serverAddress.sin_addr) <= 0) {
            perror("Invalid address or address not supported");
            exit(-1);
        }
        
        if (connect(clientSocket, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(serverAddress)) != 0) {
            perror("Connection failed");
            exit(-1);
        } else {
            std::cout << "Connected to the server" << std::endl;
            
            // Start a thread that sends heartbeats every 5 seconds
            std::thread sendHeartbeatThread([this](){
                while (true) {
                    char buffer[256];
                    
                    sprintf(buffer, "heartbeat\n");
                    
                    if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
                        perror("Error sending data");
                        break;
                    }
                    
                    std::this_thread::sleep_for(std::chrono::seconds(5));
                }
            });
            
            sendHeartbeatThread.detach(); // Detaching the thread allows it to run in background without blocking main program execution
        }
    }
};
 
int main() {
    TCPClient tcpClient;
    tcpClient.connectToServer("服务器IP地址", 8080);
    
    return 0;
}

TcpSocket+发送码流

3. TcpSocket+发送码流+解决组包问题

4. TcpSocket+心跳消息保活链路+发码流+组包不乱序

二、使用步骤

1.引入库

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值