TCP协议双向网络通讯---Python实现

打印 上一主题 下一主题

主题 963|帖子 963|积分 2889

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
       本篇文章是博主在人工智能、网络通讯等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立刻改正,还望谅解。文章分类在Python
        Python(1)---《TCP协议双向网络通讯---Python实现》
  TCP协议双向网络通讯---Python实现

目次

一、TCP协议的基本特点
二、TCP协议的毗连过程
三、TCP协议的数据传输过程
四、TCP协议的毗连关闭过程
五、TCP协议的安全挑衅与防范计谋
六、Python编程实现
4.1TcpServer服务器端代码
4.2 TcpClient客户端代码
4.3 测试结果

        TCP(Transmission Control Protocol,传输控制协议)是一种面向毗连的、可靠的、基于字节流的传输层通信协议。它工作在OSI模型的传输层,旨在确保数据在IP网络中的可靠传输。以下是对TCP协议网络通讯的具体论述:
           本文主要使用Python实现TCP协议双向网络通讯,即服务器和客户端都可以实现信息的收发,接纳多线程的方式,能够实现服务器的一对多收发信息。
  一、TCP协议的基本特点


  • 面向毗连:TCP协议在数据传输之前,必须先在通信双方之间创建毗连。这种毗连是一对一的,即一个TCP毗连只能有两个端点。毗连创建后,双方可以开始传输数据,直到毗连被关闭。(使用多线程可以实现一对多等)
  • 可靠性:TCP协议通过一系列机制来确保数据的可靠传输。这些机制包括序列号、确认应答、超时重传、流量控制等。TCP协议能够确保数据无差错、不丢失、不重复,并且按序到达。
  • 基于字节流:TCP协议将应用步伐交下来的数据当作是一连串的无布局的字节流。TCP不关心应用步伐写入数据的含义和内容,它只负责将这些数据以字节流的情势发送到对方。

 二、TCP协议的毗连过程

TCP协议的毗连过程通常被称为“三次握手”:

  • 第一次握手:客户端发送一个SYN(同步序列号)报文段到服务器,并在这个报文段中设置序列号字段的值。此时,客户端进入SYN_SENT状态。
  • 第二次握手:服务器收到客户端的SYN报文段后,发送一个SYN/ACK(同步/确认)报文段给客户端,确认客户端的SYN报文段,并设置本身的序列号。此时,服务器进入SYN_RCVD状态。
  • 第三次握手:客户端收到服务器的SYN/ACK报文段后,发送一个ACK(确认)报文段给服务器,确认服务器的SYN/ACK报文段。此时,客户端和服务器都进入ESTABLISHED(已创建毗连)状态,TCP毗连成功创建。

 三、TCP协议的数据传输过程

TCP协议在数据传输过程中,通过序列号、确认应答等机制来确保数据的可靠传输。

  • 序列号:TCP头部的序列号用于确保数据的有序传输。它表现在这个TCP段中的第一个字节的序号。在创建毗连时,双方都随机生成一个初始序列号(ISN),并以此作为后续数据传输的基准。
  • 确认应答:TCP头部中的确认应答号是接收端盼望收到的下一个字节的序列号。发送端收到确认应答后,可以以为所有在此之前的序列号的包已经被接收。
  • 超时重传:如果发送方在一定时间内没有收到接收方的确认应答,就会以为该报文段已经丢失,并重新发送该报文段。
  • 流量控制:TCP协议通过窗口巨细来控制发送方的数据流量,以适应接收方的处置惩罚本领。接收方在确认应答中告知发送方本身的窗口巨细,发送方根据这个值来控制数据的发送量。
  • 拥塞控制:TCP协议还通过拥塞控制机制来防止网络过载。当网络拥塞时,TCP会减慢数据的发送速率,以减轻网络的负担。

 四、TCP协议的毗连关闭过程

TCP协议的毗连关闭过程通常被称为“四次挥手”:

  • 第一次挥手:客户端发送一个FIN(结束毗连)报文段给服务器,表现客户端没有数据要发送了,请求关闭毗连。此时,客户端进入FIN_WAIT_1状态。
  • 第二次挥手:服务器收到客户端的FIN报文段后,发送一个ACK报文段给客户端,确认收到客户端的FIN报文段。此时,服务器进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态。
  • 第三次挥手:服务器在关闭毗连前,如果还有数据要发送给客户端,可以继续发送数据。当服务器没有数据要发送时,发送一个FIN报文段给客户端,表现服务器也没有数据要发送了,请求关闭毗连。此时,服务器进入LAST_ACK状态。
  • 第四次挥手:客户端收到服务器的FIN报文段后,发送一个ACK报文段给服务器,确认收到服务器的FIN报文段。此时,客户端和服务器都进入CLOSED状态,TCP毗连成功关闭。

 五、TCP协议的安全挑衅与防范计谋

        尽管TCP协议在筹划之初就思量到了数据传输的可靠性和安全性,但随着网络技术的不停发展,TCP协议也面临着越来越多的安全挑衅。比方,TCP创建毗连需要履历三次握手过程,这个过程中存在被恶意利用的风险;TCP协议本身并不提供加密功能,因此数据在传输过程中容易被截获和篡改。
为了保障TCP协议的安全性,可以接纳以下防范计谋:


  • 使用SSL/TLS等加密协议对TCP通信进行加密处置惩罚,确保数据在传输过程中的安全性和完备性。
  • 通过限制SYN请求频率、限制毗连数目等措施来防止SYN Flood攻击等恶意攻击。
  • 对于接收到的TCP数据包,要验证其来源是否合法,防止伪造数据

六、Python编程实现

4.1TcpServer服务器端代码

  1. import socket  # 导入socket模块,用于网络通信
  2. from threading import Thread  # 导入Thread类,用于多线程处理
  3. import time  # 导入time模块,用于时间操作
  4. import sys  # 导入sys模块,用于系统相关操作
  5. import random  # 导入random模块,用于生成随机数
  6. # 创建存储对象
  7. class Node:
  8.     def __init__(self):
  9.         self.Name = None    # 用户名
  10.         self.Thr = None     # 套接字连接对象
  11.         self.flag = 0       # 标志位
  12. class TcpServer:
  13.     user_name = {}  # 存储用户信息; dict 用户名:Node对象
  14.     def __init__(self, port):
  15.         """
  16.         初始化服务器对象
  17.         port:   服务器端口
  18.         """
  19.         self.server_port = port      # 服务器端口
  20.         self.tcp_socket = socket.socket()       # tcp套接字
  21.         self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)       # 端口重用
  22.         self.tcp_socket.bind(self.server_port)
  23.         self.sum = 0    # 总数初始值
  24.         self.flag1 = 0  # 标志位1
  25.         self.flag2 = 0  # 标志位2
  26.     def start(self):
  27.         """
  28.         启动服务器
  29.         """
  30.         self.tcp_socket.listen(100)      # 设置服务器接受的链接数量
  31.         print(self.get_time(), "系统:等待连接")
  32.         timer = Thread(target=self.timer_to_order)    # 创建定时发送线程
  33.         timer.start()
  34.         syn = Thread(target=self.syn_to_order)        # 创建同步发送线程
  35.         syn.start()
  36.         while True:
  37.             try:
  38.                 # 监听客户端的地址和发送的消息
  39.                 conn, addr = self.tcp_socket.accept()       # 返回值为套接字和网络地址
  40.             except KeyboardInterrupt:       # 按下ctrl+c会触发此异常
  41.                 self.tcp_socket.close()     # 关闭套接字
  42.                 sys.exit("\n" + self.get_time() + "系统:服务器安全退出!")        # 程序直接退出,不捕捉异常
  43.             except Exception as e:
  44.                 print(e)
  45.                 continue
  46.             # 为当前链接创建线程
  47.             t = Thread(target=self.do_request, args=(conn, ))
  48.             t.start()
  49.     def do_request(self, conn):
  50.         """
  51.         监听客户端传送的消息,并将该消息发送给所有用户
  52.         """
  53.         conn_node = Node()
  54.         while True:
  55.             recv_data = conn.recv(1024).decode('utf-8').strip()     # 获取客户端发来的数据
  56.             # print(recv_data)
  57.             info_list = recv_data.split(" ")        # 切割命令
  58.             # print(info_list)
  59.             # 如果接收到命令为exit,则表示该用户退出,删除对应用户信息,关闭连接
  60.             if recv_data == "exit":
  61.                 msg = self.get_time() + " 系统:用户" + conn_node.Name + "退出控制系统!"
  62.                 print(msg)
  63.                 self.send_to_other(conn_node.Name, msg)
  64.                 conn.send('exit'.encode("utf-8"))
  65.                 self.user_name.pop(conn_node.Name)
  66.                 conn.close()
  67.                 break
  68.             else:
  69.                 try:
  70.                     A = info_list[-2], info_list[-1]
  71.                 except IndexError:
  72.                     conn.send((self.get_time() + ' 系统:无法识别您的指令,请重新输入!').encode('gb2312'))
  73.                     continue
  74.             if info_list[-1] == '-n':
  75.                 # 新用户注册
  76.                 print(self.get_time() + ' 系统:' + info_list[0] + '连接成功')
  77.                 data_info = self.get_time() + ' 系统:' + info_list[0] + '加入了控制系统'
  78.                 self.send_to_all(data_info)
  79.                 conn.send('OK'.encode('utf-8'))
  80.                 conn_node.Name = info_list[0]
  81.                 conn_node.Thr = conn
  82.                 self.user_name[info_list[0]] = conn_node
  83.             elif info_list[-1] == '-ta':
  84.                 # 群发消息
  85.                 # msg = self.get_time() + ' %s:' % conn_node.Name + ' '.join(info_list[:-1])
  86.                 self.sum = self.sum + int(info_list[0])
  87.                 msg = self.get_time() + ' %s:贡献' % conn_node.Name + ' '.join(info_list[:-1]) + '。总数:%d' % self.sum
  88.                 self.send_to_all(msg)
  89.             elif info_list[-1] == '-tas':
  90.                 conn_node.flag = 1
  91.                 self.sum = self.sum + int(info_list[0])
  92.                 msg = self.get_time() + ' %s:贡献' % conn_node.Name + ' '.join(info_list[:-1]) + '。总数:%d' % self.sum
  93.                 self.send_to_all(msg)
  94.     def send_to_all(self, msg):
  95.         """
  96.         对所有用户发送消息
  97.         """
  98.         print(msg)
  99.         for i in self.user_name.values():
  100.             i.Thr.send(msg.encode('utf-8'))
  101.     def send_to_other(self, name, msg):
  102.         """
  103.         对除了当前发送信息的用户外的其他用户发送消息
  104.         """
  105.         # print("收到消息:" + msg)
  106.         for n in self.user_name:
  107.             if n != name:
  108.                 self.user_name[n].Thr.send(msg.encode('utf-8'))
  109.             else:
  110.                 continue
  111.     def get_time(self):
  112.         """
  113.         返回当前系统时间
  114.         """
  115.         return '[' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ']'
  116.     # 服务器定时发送指令
  117.     def timer_to_order(self):
  118.         while True:
  119.             for i in self.user_name.values():
  120.                 msg = '{}'.format(random.randint(1, 10)) + ' -ord'
  121.                 print('\n给客户端发送定时指令: %s' % msg)
  122.                 i.Thr.send(msg.encode('utf-8'))
  123.             time.sleep(30)  # 30s定时发送一次
  124.     # 服务器同步发送指令
  125.     def syn_to_order(self):
  126.         while True:
  127.             flag_sum = 0  # 标志位总和
  128.             for key in self.user_name:  # 获得字典的键
  129.                 flag_sum += self.user_name[key].flag  # 计算各客户端的flag位
  130.             time.sleep(0.01)  # 延迟10s,防止迭代时,字典数量改变
  131.             if flag_sum == len(self.user_name) and flag_sum != 0:  # 判断服务器是否都接受到flag标志
  132.                 end_flag = 1  # 终值标志位
  133.             else:
  134.                 end_flag = 0
  135.             if end_flag:
  136.                 print("\n")
  137.                 for i in self.user_name.values():
  138.                     msg = '{}'.format(random.randint(1+self.sum, 10+self.sum)) + ' -ord'
  139.                     print('===给客户端发送特殊指令: %s' % msg)
  140.                     i.Thr.send(msg.encode('utf-8'))
  141.                     i.flag = 0
  142. if __name__ == '__main__':
  143.     HOST = "127.0.0.1"  # 主机回送地址,测试使用
  144.     # HOST = '192.168.8.111'  # 局域网ip地址,实际情况使用
  145.     POST = 9999
  146.     server = TcpServer((HOST, POST))
  147.     server.start()
复制代码
4.2 TcpClient客户端代码

      (可以新建多个客户端)
  1. import socket  # 导入socket模块,用于网络通信
  2. from threading import Thread  # 导入Thread类,用于多线程处理
  3. import time  # 导入time模块,用于时间操作
  4. class TcpClient:
  5.     server_addr = ('127.0.0.1', 9999)  # 服务器地址和端口
  6.     order = 2  # 初始指令数
  7.     def __init__(self):
  8.         self.tcp_cli_socket = socket.socket()  # 创建TCP客户端套接字
  9.     def msg_recv(self):
  10.         """
  11.         接收数据
  12.         """
  13.         while True:
  14.             data = self.tcp_cli_socket.recv(1024).decode('utf-8').strip()  # 接收数据并解码
  15.             info_list = data.split(" ")  # 切割命令
  16.             if data == "exit":
  17.                 print('客户端退出')
  18.                 self.tcp_cli_socket.close()
  19.                 break
  20.             if info_list[-1] == '-ord':
  21.                 if int(info_list[0])/2.0 == int(int(info_list[0])/2):
  22.                     print('\033[1;32m通过\033[0m')  # 在控制台中打印通过信息(绿色)
  23.                     print("接收可行指令,并更新标志数为:", int(info_list[0]))  # 打印接收到的指令信息
  24.                     self.order = int(int(info_list[0])/2.0)  # 更新指令数
  25.                 else:
  26.                     print('不通过')  # 打印不通过信息
  27.             else:
  28.                 print(data)  # 打印其他接收到的数据
  29.     def msg_send(self):
  30.         """
  31.         发送数据
  32.         """
  33.         while True:
  34.             data_info = input("请发送指令:")  # 用户输入指令
  35.             if data_info == "exit":
  36.                 self.tcp_cli_socket.send(data_info.encode("utf-8"))  # 发送退出指令
  37.                 break
  38.             else:
  39.                 self.tcp_cli_socket.send((data_info + ' -ta').encode("utf-8"))  # 发送带有标志的指令
  40.     def order_send(self):
  41.         """
  42.         定时发送指令
  43.         """
  44.         while True:
  45.             time.sleep(5)  # 每隔5秒发送一次指令
  46.             self.tcp_cli_socket.send(('{}'.format(self.order) + ' -tas').encode("utf-8"))  # 发送同步指令
  47.             print("给服务器发送指令:%d" % self.order)  # 打印发送的指令数
  48.     def start(self):
  49.         """
  50.         连接服务器
  51.         """
  52.         try:
  53.             self.tcp_cli_socket.connect(self.server_addr)  # 连接服务器
  54.         except Exception as e:
  55.             print("连接失败,请重试!")
  56.             self.tcp_cli_socket.close()
  57.             print(e)
  58.             return
  59.         while True:
  60.             name = input("输入客户端编号:")  # 输入客户端编号
  61.             self.tcp_cli_socket.send((name + ' -n').encode('utf-8'))  # 发送注册指令
  62.             data = self.tcp_cli_socket.recv(128).decode('utf-8')  # 接收服务器返回信息
  63.             print(data)  # 打印返回信息
  64.             if data == "OK":
  65.                 print("你已成功进入服务器")
  66.                 break
  67.             else:
  68.                 print(data)
  69.         t = Thread(target=self.msg_recv)  # 创建信息接收线程
  70.         t.start()
  71.         t1 = Thread(target=self.msg_send)  # 创建信息发送线程
  72.         t1.start()
  73.         t2 = Thread(target=self.order_send)  # 创建定时指令发送线程
  74.         t2.start()
  75. if __name__ == '__main__':
  76.     client = TcpClient()
  77.     client.start()
复制代码
4.3 测试结果

运行服务器端:

运行客户端:


        文章若有不当和不正确之处,还望理解与指出。由于部门笔墨、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者私信联系作者。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦见你的名字

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表