浅谈TCP通信过程

传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的运输层通信协议。在简化的计算机网络OSI模型中,它完成运输层所指定的功能。TCP提供一种面向连接的、可靠的字节流服务。
TCP通信设置主要分为TCP的服务端和客户端
tcp服务端

  1. 创建一个tcp流式套接字
  2. 绑定本机的IP和端口号
  3. 将套接字转为监听套接字
  4. 套接字等待客户端请求
  5. 消息的收发
    代码如下
#import RPi.GPIO as GPIO
from _socket import socket
from socketserver import StreamRequestHandler, ThreadingTCPServer
import time
import threading


class LedTcpServer(ThreadingTCPServer):
    def __init__(self,serveraddress,ClinetDataHandler):
        self.daemon_threads = True
        self.allow_reuse_address = True
        ThreadingTCPServer.__init__(self,serveraddress,ClientDataHandler)
    
            
    def listClient(self):
        if (self._wfiles.count()>0):
            index = 0
            for wfile in self._wfiles :
                print(index+":"+wfile+"\r\n")
                index += 1
                
    def write(self,socketfile,ledCmd):
        if (self.wfile.closed!=True):
            self.wfile.writeline(ledCmd)

class ClientDataHandler(StreamRequestHandler): 
    _clientlist = []
    _wfiles = []
    _clientdata = ""  
    def handle(self):
        #StreamRequestHandler.handle(self)
        _Flag = True
        while _Flag:                       
            _clientAdd = self.client_address
            _wfile = self.wfile
            if (_wfile not in self._wfiles):
                self._wfiles.append(_wfile)
                self._clientlist.append(_clientAdd)
                msg = "\r\n"+str(_clientAdd)+"连接成功"
                print(msg)
        
    def finish(self):
        _clientAdd = self.client_address
        if (_clientAdd in self._clientlist):
            self.clientlist.remove(_clientAdd)

def CmdInterface():
    Flag = True
    while Flag:
        try:
            controller = input("cmd>")
            if (controller!=""):
#                 if (controller.strip().lower()=="on"):
#                     socketfile = input("please choice a socket useage list cmd")
#                     LedTcpServer.write("on")
#                 elif (controller.strip().lower()=="off"):
#                     LedTcpServer.write("off")
                if (controller.strip().lower()=="help"):
                    print("firset useage list cmd to get the client ip and port")
                    print("then useage cmd index:cmd to controller the led")
                    print("cmd index:1 LedOn")
                    print("cmd index:2 LedOff")
                    print("cmd index:other number do onthing!")
                elif (controller.strip().lower()=="list"):
                    #print(ClientDataHandler._wfiles)
                    print("please select a index\r\n")
                    print("index:socket")
                    index = 0
                    #print(ClientDataHandler._clientlist)
                    out = {}
                    for _clientadd in ClientDataHandler._clientlist:
                        out[index] = _clientadd
                        index +=1
                    print(out)
                        #_wfile.write(b"hello")
                elif (":" in controller):
                    print(controller)
                    ledControllcmd = controller.split(":")
                    index = ledControllcmd[0]
                    ledcmd = ledControllcmd[1]
                    print(ledcmd)
                    if (str(ledcmd).isnumeric() and str(index).isnumeric()):                        
                        #ClientDataHandler._wfiles[int(index)].write(b"on1")
                        if (str(ledcmd)=="1"):
                            ClientDataHandler._wfiles[int(index)].write(b"on")
                        if (str(ledcmd)=="2"):
                            ClientDataHandler._wfiles[int(index)].write(b"off")                    
                else:
                    break 
            else:
                print("please input data")
        except Exception:
            pass   

            
            

                
                
if (__name__=="__main__"):
    print("服务开启1")
    
    cmd = threading.Thread(target=CmdInterface);
    cmd.setDaemon(False)
    cmd.start()
    
    address = ('',11235)
    # 该方法继承自 TcpServer的 __init__,ThreadingTCPServer继承自(ThreadingMixIn, TCPServer),serve_forever()为Tcpserver父类的BaseServer的方法
    ledServer = LedTcpServer(address,ClientDataHandler)
    ledServer.serve_forever()

tcp客户端
创建客户端套接字要和访问的服务器的套接字类型相同。
连接服务器
和服务器进行通信
关闭套接字
代码如下

import RPi.GPIO as GPIO
import socket
import threading


class LedNetClient:
    def __init__(self,remoteHost=('127.0.0.1',11235)):
        try:            
            client = socket.socket()
            client.connect(remoteHost)
           
            print("启动成功")
            Flag = True
            while Flag:
                ledcmd = client.recv(1024)
                ledcmd = ledcmd.strip().decode()
#                 print(ledcmd+"a")
                if (ledcmd=="on"):
                    print("get server cmd:"+ledcmd)
                    ledcontr = LedOpreator()
                    ledcontr.ledControll("on")
     
                elif(ledcmd=="off"):
                    print("get server cmd:"+ledcmd)
                    ledcontr = LedOpreator()
                    ledcontr.ledControll("off")
                else:
                    pass              
        except Exception:
            print(Exception)
        finally:
            pass
                     

class LedOpreator:
    pin = 11
    def __init__(self,pin=11):
        self.pin = pin
        GPIO.setmode(GPIO.BOARD)
        GPIO.setwarnings(False)
        GPIO.setup(self.pin,GPIO.OUT)
         
    def ledControll(self,cmd="on"):
        if (cmd.lower()=="on"):
            GPIO.output(self.pin,GPIO.HIGH)
        elif(cmd.lower()=="off"):
            GPIO.output(self.pin,GPIO.LOW)
        else:
            pass
        
def dosInterface():
    Flag = True
    print("please input the remote server ip and port like this:127.0.0.1:10000")
    while Flag:       
        remoteHost = input("REMOTEHOST>")
        if (":" in str(remoteHost)):
            remoteHost = remoteHost.split(":")
            ip = remoteHost[0]
            port = remoteHost[1]
            hostname =(ip,int(port))
            print(hostname)
            ledclient = LedNetClient(hostname)
#             ledclient.handlerData(ledclient)
        elif(remoteHost.strip()=="1"):
            ledcontr = LedOpreator()
            ledcontr.ledControll("on")
        elif(remoteHost.strip()=="2"):
            ledcontr = LedOpreator()
            ledcontr.ledControll("off")
        else:
            ledclient = LedNetClient()
#             print("please input the remote server ip and port like this:127.0.0.1:10000")
        
if (__name__=="__main__"):    
    
    dosui = threading.Thread(target=dosInterface)
    dosui.setDaemon(False)
    dosui.start()

Tcp整个通信过程中的几次握手
建立连接时的三次握手
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)
Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。
完成三次握手,主机A与主机B开始传送数据。

结束连接的四次握手
第一次,客户端发送一个FIN,用来关闭客户端到服务器的数据传送,然后等待服务器的确认。其中终止标志位FIN=1,序列号seq=u。
第二次,服务器收到这个FIN,它发送一个ACK,确认ack为收到的序号加一。
第三次,关闭服务器到客户端的连接,发送一个FIN给客户端。
第四次,客户端收到FIN后,并发回一个ACK报文确认,并将确认序号seq设置为收到序号加一。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

猜你喜欢

转载自blog.csdn.net/qq_41152634/article/details/82783216