客户端通过服务器进行TCP通信(三)

news2024/9/21 2:46:13

一. 对TCP的基础讲解

服务端

1. 首先创建一个套接字,TCP是面向字节流的套接字,故需要使用SOCK_STREAM

2. 然后使用bind()函数将套接字与服务器地址关联(如果是在本地测试,直接将地址设置为217.0.0.1或者localhost,端口号为10000)

3. listen()将套接字设置为监听状态

3. 等待,参数为最大排队数

4. 在循环中,调用accept()等待客户端的消息连接,如果有客户端进行连接,那么accept()函数会返回一个打开的连接与客户端地址

6. 指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据

7. 通过sendall()进行回传客户端数据

8. 传回数据后,与当前的客户端通信就算完成了。需要使用close()进行关闭清理

客户端

1. 创建一个套接字

2. 使用connect()函数连接到服务器

3. 通过sendall()向服务器发送数据

4. 通过recv()接受服务器传递回的数据

5. 交互完成之后,使用close()关闭清理

二. 编写Python程序

2.1 Python实现一个服务端和一个客户端连接

服务端代码

# coding=gb2312
import socket
 
socket_server = socket.socket()
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# 等待客户端连接,accept方法返回二元元组(连接对象, 客户端地址信息)
print(f"服务端已开始监听,正在等待客户端连接...")
conn, address = socket_server.accept()
print(f"接收到了客户端的连接,客户端的信息:{address}")
 
# 接受客户端信息,使用客户端和服务端的本次连接对象,而非socket_server
while True:
    # 接收消息
    data: str = conn.recv(1024).decode("UTF-8")
    print(f"客户端发来的消息是:{data}")
    # 回复消息
    msg = input("请输入你要回复客户端的消息:")
    if msg == 'exit':
        break
    conn.send(msg.encode("UTF-8"))  # encode将字符串编码为字节数组对象
 
# 关闭连接
conn.close()
socket_server.close()

客户端代码

# coding=gb2312
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务器
socket_client.connect(("localhost", 8888))
 
while True:
    send_msg = input("请输入要发送给服务端的消息:")
    if send_msg == "exit":
        break
    # 发送消息
    socket_client.send(send_msg.encode("UTF-8"))
    # 接受消息
    recv_data = socket_client.recv(1024).decode("UTF-8")    # 1024是缓冲区大小,一般就填1024, recv是阻塞式
    print(f"服务端回复的消息是:{recv_data}")
 
# 关闭连接
socket_client.close()

运行之后我们就实现了客户端和服务端的通信,但此时只能有一个客户端连接到服务端,如果想实现多个客户端,就需要修改服务端listen()的参数,允许更多的客户端连接,下面进行讲解。

2.2 Python实现一个服务端和多个客户端连接

服务端代码

# coding=gb2312
import socket
import threading
 
 
def create_server_socket(host, port):
    socket_server = socket.socket()
    socket_server.bind((host, port))
    socket_server.listen(5)
    print(f"服务端已启动,地址{host},端口{port}")
    print(f"正在等待客户端连接...")
    # 开启多线程,收发来自多个客户端的数据
    num = 0     # 标记客户端的编号
    while True:
        num += 1
        conn, address = socket_server.accept()
        print(f"服务端已接受到客户端 {num}号 的连接请求,客户端信息:{address}")
        client_handler = threading.Thread(target=handle_client, args=(conn, address, num))
        client_handler.start()
 
 
# 处理收发数据
def handle_client(conn, address, num):
    while True:
        # 接收客户端发来的数据
        data_from_client: str = conn.recv(1024).decode("UTF-8")
        print(f"客户端 {num}号:{address}发来的消息是:{data_from_client}")
        # 发送消息到客户端
        msg = input(f"请输入你要回复客户端 {num}号:{address}的消息:")
        if msg == 'exit':
            break
        conn.send(msg.encode("UTF-8"))  # encode将字符串编码为字节数组对象
    conn.close()
 
 
if __name__ == '__main__':
    server_host = input("请输入服务端Host:")
    server_port = int(input("请输入服务端port:"))
    create_server_socket(server_host, server_port)

客户端代码

# coding=gb2312
import socket
 
 
def create_client(host, port):
    socket_client = socket.socket()
    socket_client.connect((host, port))
    # 发送、接受数据
    while True:
        msg = input(f"请输入客户端1发送给服务端{host}:{port}的数据:")
        if msg == "exit":
            break
        # 发送数据到服务端
        socket_client.send(msg.encode("UTF-8"))
        # 接收服务端的数据
        data_from_server = socket_client.recv(1024).decode("UTF-8")
        print(f"客户端接收到服务端的消息:{data_from_server}")
    socket_client.close()
 
 
if __name__ == '__main__':
    server_host = input("请输入想要连接的服务端Host:")
    server_port = int(input("请输入想要连接的服务端port:"))
    create_client(server_host, server_port)

三. 移植Python程序

注意,服务器上的python版本和vscode上使用的服务器版本一定要一致。因为上述代码都是在Python3下写的,且我服务器的的python版本是python2,所以下面对代码进行一定的更改。

# coding=gb2312
# -*- coding: utf-8 -*-
# import os
# os.environ["CUDA_VISIBLE_DEVICES"] = "0, 1"
from __future__ import print_function
import socket
import threading

 
def create_server_socket():
    socket_server = socket.socket()
    socket_server.bind(("localhost",50000))
    # socket_server.bind(("47.116.118.86",5000))
    socket_server.listen(65000)
    print("正在等待客户端连接...")
    # 开启多线程,收发来自多个客户端的数据
    num = 0     # 标记客户端的编号
    while True:
        num += 1
        conn, address = socket_server.accept()
        print("服务端已接受到客户端 {}号 的连接请求,客户端信息:{}".format(num,address))
        client_handler = threading.Thread(target=handle_client, args=(conn, address, num))

        client_handler.start()
 
 
# 处理收发数据
def handle_client(conn, address, num):
    while True:
        # 接收客户端发来的数据
        data_from_client = conn.recv(1024).decode("UTF-8")
        print("客户端 {}号:{}发来的消息是:{}".format(num,address,data_from_client))
        # 发送消息到客户端
        #msg = raw_input("请输入你要回复客户端 {}号:{}的消息:".format(num,address))
        msg = data_from_client
        if msg == 'exit':
            break
        conn.send(msg.encode("UTF-8"))  # encode将字符串编码为字节数组对象
    conn.close()
 
 
if __name__ == '__main__':
    create_server_socket();
    # create_server_socket("172.19.84.229", 8080)
    # create_server_socket("", 8080)

3.2 在服务器运行Python程序

在py文件中加入以下代码:

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0, 1"

添加后,在服务器直接运行python xxxx.py,就可以运行这个Python文件了。

四. 实现服务端运行python服务端程序,与客户端通信

在阿里云服务器监听服务器的内网IP,例如172.22.71.222,端口号设置为8080.

在客户端去连接的不是服务器的内网IP,而是云服务器的公网IP,如47.112.113.43,端口号也设置为8080

这样便能连接成功

这样我们就可以在云服务器作为服务端,在自己本机作为客户端,实现TCP传输。

如果我们要实现客户端到客户端的通信的话,可以在服务端开辟多个线程,去处理客户端的数据。

此时主线程负责对发起请求的客户创建链接,并且将每个用户对应的链接保存到一个字典中去,方便调用。对于每个用户链接,都创建两个子线程,一个子线程用来发送数据,另外一个子线程用来接收数据。

但这种方法如果客户端多的话,就对资源消耗很大,因此这个项目我就摒弃了这个方法,从而采用直接从数据库中获取数据,实现多个客户端去获取云服务器的MYSQL数据库的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1927882.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mac电脑下运行java命令行出现:错误: 找不到或无法加载主类

mac 电脑 问题复现 随手写了一个main方法,想用命令行操作 进入 BlockDemo.java 所在目录: wnwangnandeMBP wn % cd /Users/wn/IdeaProjects/test/JianZhiOffer/src/main/java/com/io/wn wnwangnandeMBP wn % ls -l total 16 -rw-r--r-- 1 wangnan …

前端框架学习之 搭建vue2的环境 书写案例并分析

目录 搭建vue的环境 Hello小案例 分析案例 搭建vue的环境 官方指南假设你已经了解关于HTML CSS 和JavaScript的中级知识 如果你刚开始学习前端开发 将框架作为你的第一步可能不是最好的主意 掌握好基础知识再来吧 之前有其他框架的使用经验会有帮助 但这不是必需的 最…

【JavaScript 算法】二分查找:快速定位目标元素

🔥 个人主页:空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 二分查找(Binary Search)是一种高效的查找算法,适用于在有序数组中快速定位目标元素。相比于线性查找,二分查找…

【java】力扣 买卖股票的最佳时机II

文章目录 题目链接题目描述思路代码 题目链接 122.买卖股票的最佳时机II 题目描述 思路 这道题和121.买卖股票的最佳时机 有所不同,不同点在于,这道题的股票可以多次买卖(但是要在买之前先卖掉) 详细思路请看链接的文章【java】力扣 买卖股票的最佳时…

Milvus核心设计(2)-----TSO机制详解

目录 背景 动机 Timestamp种类及使用场景 Guarantee timestamp Service timestamp Graceful time Timestamp同步机制 主流程 时间戳同步流程 背景 Milvus 在设计上突出了分布式的设计,虽然Chroma 也支持分布式的store 与 query。但是相对Milvus来说,不算非常突出。…

Linux--USB驱动开发(二)插入USB后的内核执行程序

一、USB总线驱动程序的作用 a)识别USB设备 1.1 分配地址 1.2 并告诉USB设备(set address) 1.3 发出命令获取描述符 b)查找并安装对应的设备驱动程序 c)提供USB读写函数 二、USB设备工作流程 由于内核自带了USB驱动,所以我们先插入一个U…

SQL中的谓词与谓词下推

在 SQL 查询中,谓词(Predicate)是用来对数据进行过滤的条件。它们决定了数据从数据库表中被选择的条件。理解和正确使用 SQL 谓词对于编写高效查询至关重要。 目录 什么是谓词?一个真实的故事SQL 谓词的代码示例比较谓词逻辑谓词…

服务客户,保证质量:腾讯云产品的质量实践

分享主题是“服务客户,保证质量”。自从20年开始,我们把质量提升到了一个前所未有的高度。为什么会如此重视质量呢?在竞争激烈和复杂的市场环境中,产品质量对于企业的重要性不言而喻。一旦出现了质量事故,对客户和企业…

SCI二区|母亲优化算法(MOA)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年,I Matoušov受到母亲与孩子之间的人际互动启发,提出了母亲优化算法(Mother Optimization Algorithm, MOA)。 2.算法原理 2.1算法思…

PHP中的函数与调用:深入解析与应用

目录 一、函数基础 1.1 函数的概念 1.2 函数的定义 1.3 函数的调用 二、PHP函数的分类 2.1 内置函数 2.2 用户自定义函数 2.3 匿名函数 2.4 递归函数 2.5 回调函数 2.6 魔术方法 三、函数的参数与返回值 3.1 参数传递 3.2 返回值 四、函数的高级特性 4.1 可变函…

【HarmonyOS】鸿蒙中如何获取用户相册图片?photoAccessHelper.PhotoViewPicker

【HarmonyOS】鸿蒙中如何获取用户相册图片?photoAccessHelper.PhotoViewPicker 前言 有同学私聊我说,之前的博客文章提到的没有HarmonyOS白名单帐号,如何在OpenHarmony Gitee开发仓里学习API接口。需要注意一个点,默认看到的文档…

07 物以类聚 基于特征的七种算法模型

你好,我是大壮。在 06 讲中,我们介绍了协同过滤(CF)算法,它主要通过用户行为构建用户物品共现矩阵,然后通过 CF 算法预测结果实现个性化推荐。其实,除了利用用户行为特征之外,我们还…

决策树(ID3,C4.5,C5.0,CART算法)以及条件推理决策树R语言实现

### 10.2.1 ID3算法基本原理 ### mtcars2 <- within(mtcars[,c(cyl,vs,am,gear)], {am <- factor(am, labels c("automatic", "manual"))vs <- factor(vs, labels c("V", "S"))cyl <- ordered(cyl)gear <- ordered…

VMware与centos安装

目录 VM安装 安装centos VM安装 VMware Workstation Pro是VMware&#xff08;威睿公司发布的一袋虚拟机软件&#xff09;&#xff0c;它主要功能是可以给用户在单一的桌面上同时运行不同的操作系统&#xff0c;也是可以进行开发、测试、部署新的应用程序的最佳解决方案。 开始…

力扣144题:二叉树的先序遍历

给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输出&am…

跳妹儿学编程之ScratchJr(9):程序控制积木篇—短跑比赛

跳妹儿学编程之ScratchJr(7)&#xff1a;动作积木篇—爸爸去散步 跳妹儿学编程之ScratchJr(8)&#xff1a;外观积木篇—捉迷藏 跳妹儿学编程之ScratchJr(9)&#xff1a;程序控制积木篇—短跑比赛 引言 在之前的一篇文章中&#xff0c;我们了解了ScratchJr的动作积木和外观积…

排序(三)——归并排序(MergeSort)

欢迎来到繁星的CSDN&#xff0c;本期内容主要包括归并排序(MergeSort)的实现 一、归并排序的主要思路 归并排序和上一期讲的快速排序很像&#xff0c;都利用了分治的思想&#xff0c;将一整个数组拆成一个个小数组&#xff0c;排序完毕后进行再排序&#xff0c;直到整个数组排序…

php反序列化--2--PHP反序列化漏洞基础知识

一、什么是反序列化&#xff1f; 反序列化是将序列化的字符串还原为PHP的值的过程。 二、如何反序列化 使用unserialize()函数来执行反序列化操作 代码1&#xff1a; $serializedStr O:8:"stdClass":1:{s:4:"data";s:6:"sample";}; $origina…

autoware.universe源码略读(3.15)--perception:object_merger

autoware.universe源码略读3.15--perception:object_merger Overviewnode&#xff08;enum&#xff09;MSG_COV_IDX&#xff08;Class&#xff09;ObjectAssociationMergerNode&#xff08;Func&#xff09;isUnknownObjectOverlapped&#xff08;Func&#xff09;convertListT…

Directory Opus 13 专业版(Windows 增强型文件管理器)值得购买?

在使用电脑时&#xff0c;总少不了和文件打交道。系统自带的 Explorer 资源管理器功能又非常有限&#xff0c;想要拥有一个多功能文件管理器吗&#xff1f; Directory Opus 是一款老牌多功能文件管理器&#xff0c;能很好地接管 Windows 资源管理器。 接管资源管理器 Directo…