zoukankan      html  css  js  c++  java
  • python socket原理 及socket如何使(tcp udp协议)

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

    建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API)

    主要内容:

    • 1.基于TCP协议下的socket通信流程
    • 2.基于UDP协议下的socket通信流程
    • 3.粘包现象

    1.基于TCP协议下的socket通信流程

    (1)TCP和UDP的对比

    TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;文件传输程序。

    UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文(数据包),尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

    应用层
        对应协议:HTTP,SMTP,POP3
        对应设备:无
    传输层
        对应协议:TCP与UDP协议
        对应设备:四层交换机,四层的路由器
    网络层
        对应协议:IP协议
        对应设备:路由器,三层交换机
    数据链路层
        对应协议:arp协议
        对应设备:网桥,以太网交换机,网卡
    物理层
        对象协议:无
        对应设备:中继器,集线器,双绞线


    3次握手

    client syn1 随机产生seq=j 进入syn_sent

    server 收到syn1 将标志位synACK都置为1 ack=j+1 产生seq=K 进入syn_rcvd状态

    client收到后检查ack是不是j+1 如果是将标志位synack都置为1 ack=K+1 双方进established

    
    

    4次断开

    Client发送 fin 进入fin_wait_1状态

    Server 收到fin 发送ack 确认序列号+1 close_wait状态  #告诉客户端你先等一下,我看下我的管道里面是否还有信息,如果有给处理完

    Server发送一个fin关闭连接  server进入 last_ack状态

    Client收到fin进入 time_wait 发送ackserver server进入closed(刻漏声的)

     TCP 和UDP下socket差异对比图

    (2) TCP协议下的socket通信流程

    具体的通信流程

    • 先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。
    • 在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。
    • 客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

     TCP服务器端

    import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1',8898))  #把地址绑定到套接字
    sk.listen()          #监听链接
    conn,addr = sk.accept() #接受客户端链接 执行这句,表示建立了3次握手
    ret = conn.recv(1024)  #接收客户端信息
    print(ret)       #打印客户端信息
    conn.send(b'hi')        #向客户端发送信息
    conn.close()       #关闭客户端套接字 执行这句,表示经历了4次挥手
    sk.close()        #关闭服务器套接字(可选) 关闭套接字,不在接收客户端请求。
    
    tcp_server.py

    TCP 客户端

    import socket
    sk = socket.socket()           # 创建客户套接字
    sk.connect(('127.0.0.1',8898))    # 尝试连接服务器
    sk.send(b'hello!')
    ret = sk.recv(1024)         # 对话(/接收)
    print(ret)
    sk.close()            # 关闭客户套接字
    
    tcp_client.py

    #############udp###################

    UDP server 通信

    import socket
    udp_server = socket.socket(type=socket.SOCK_DGRAM) #设置udp方式
    ip_port = ('127.0.0.1',8002)
    udp_server.bind(ip_port)#把地址绑定到套接字
    from_client_msg,client_addr = udp_server.recvfrom(1024)#服务器接收服务发来的值
    
    udp_server.sendto(b'fuwuqi',client_addr)#服务器说 发送给客户端
    
    print(from_client_msg,client_addr)
        #打印服务器说的话  客户端的地址

    UDP client 通信

    import socket
    udp_client = socket.socket(type=socket.SOCK_DGRAM)#使用udp方式
    ip_port = ('127.0.0.1',8002)##把地址绑定到套接字
    udp_client.sendto(b'hello',ip_port)#客户端 向服务器端发动hello ip地址端口
    
    from_server_msg,server_addr = udp_client.recvfrom(1024)#客户端接收服务发来的值
    print(from_server_msg,server_addr)#打印出来

    ################udp  while方式+名字#################

    ####server
    import socket
    lst = {'egon': '33[1;31m', 'yuan': '33[1;34m'}
    sk = socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1', 9090))
    while True:
        msg, client_addr = sk.recvfrom(1024)  # udp协议不用建立链接
        name, mesg = msg.decode('utf-8').split(':')
        color = lst.get(name.strip(), '')
        print('%s%s33[0m' % (color, msg.decode('utf-8')))
        inp = input('>>>')
        sk.sendto(inp.encode('utf-8'), client_addr)
    sk.close()

    client

    import socket
    sk = socket.socket(type=socket.SOCK_DGRAM)
    name = input('请输入名字: ')
    while True:
        inp = input('请输入发送内容: ')#名字
        sk.sendto(('%s : %s' % (name, inp)).encode('utf-8'), ('127.0.0.1', 9090))
        msg, addr = sk.recvfrom(1024)
        print(msg.decode('utf-8'))
    sk.close()

    #################写出面向对象的实现方法

    ###mysocket.py
    from socket import *  # 导入socket模块
    class Mysocket(socket):  # 继承socket
        def __init__(self,coding='utf-8'):  # 默认编码为utf-8
            self.coding = coding
            super().__init__(type=SOCK_DGRAM)  # 设定为udp协议
        def my_recv(self,num):  # num表示最大字节,比如1024
            msg,addr = self.recvfrom(num)
            return msg.decode(self.coding),addr  # 返回解码后的接收信息
        def my_send(self,msg,addr):  # msg和addr分别表示发送信息和连接ip:端口
            return self.sendto(msg.encode(self.coding),addr)  # 发送编码后的信息
    ######Server02.py
    from mysocket import Mysocket
    sk = Mysocket()  # 可以指定编码,默认为utf-8
    lst = {'eva': '33[1;31m', 'yuan': '33[1;34m'}
    sk.bind(('127.0.0.1', 9090))
    while True:
        msg, client_addr = sk.my_recv(1024)  # udp协议不用建立链接
        name, mesg = msg.split(':')
        color = lst.get(name.strip(), '')
        print('%s%s33[0m' % (color, msg))
        inp = input('>>>')
        sk.my_send(inp, client_addr)
    sk.close()
    ##client02
    from mysocket import Mysocket
    sk = Mysocket()
    name = input('请输入名字: ')
    while True:
        inp = input('请输入发送内容: ')
        sk.my_send(('%s : %s' % (name, inp)), ('127.0.0.1', 9090))
        msg, addr = sk.my_recv(1024)
        print(msg)
    sk.close()

     ################时间同步服务 

    import time
    import socket
    sk = socket.socket(type = socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',9090))#绑定端口
    while True:
        msg,addr = sk.recvfrom(1024)#接收
        print(msg,addr)
        sk.sendto(time.strftime(msg.decode('utf-8')).encode('utf-8'),addr)#发送
    sk.close()
    
    # a=time.strftime('%Y/%m/%d %H:%M:%S')
    # print(a)
    import time
    import socket
    
    sk = socket.socket(type=socket.SOCK_DGRAM)
    while True:
        sk.sendto('%Y/%m/%d %H:%M:%S'.encode('utf-8'), ('127.0.0.1', 9090))  # 执行时间格式
        ret, addr = sk.recvfrom(1024)#接收
        print(addr,ret.decode('utf-8'))
        time.sleep(1)  # 暂停1秒执行
    sk.close()
    不怕大牛比自己牛,就怕大牛比自己更努力
  • 相关阅读:
    java 多级图的最短路径
    在dos中编译java文件
    apollo客户端的长轮询机制的原理
    Apollo配置中心动态生效实现原理
    jmx_exporter+prometheus+grafana实现kafka metric监控
    XXL-JOB(1) 分布式任务系统选型和XXL-JOB介绍,这篇文章相当的经典呀
    grafana根据不同prometheus server统计数据
    XXL-JOB的使用教程
    普罗米修斯官方文档
    Prometheus标签的管理
  • 原文地址:https://www.cnblogs.com/zaizai1573/p/10217447.html
Copyright © 2011-2022 走看看