python网络编程

作者: Cache_wood | 来源:发表于2021-12-13 10:36 被阅读0次

    @[toc]

    网络结构

    • ISP
      • Internet Service Provider
      • 一个或多个分组交换机在多段通信链路组成的网络
      • 提供不同类型的网络接入
      • 独立运营
    • ISP分层
      • 第一层:因特网主干
        Sprint,AT&T,Level3
      • 第二层:具有区域性或国家性覆盖规模,引导流量通过,也可以跟其他第二层ISP交换流量
        Provider-custoner
        Peer-peer
      • 较低层:通过一个或多个第二层ISP与更大的因特网连接

    网络结构

    • 接入点POP
      ISP与ISP的连接点,由一个或多个路由器组成
    • 网络接入点NAP
      由第三方通信公司或因特网主干提供
    • 接入方式


    • Socket
      应用层与TCP/IP协议族通信的中间软件抽象层
    • TCP socket编程
    函数 作用
    AF_INET 使用IPv4协议
    AF_INET6 使用IPv6协议
    SOCK_STREAM 指定使用面向流的TCP协议
    bind() 绑定端口,端口号不小于1024
    listen() 监听窗口,并指定等待连接的最大数量
    accept() 等待并返回一个客户端连接
    connect() 主动连接服务端
    recv() 接收TCP数据
    send() 发送TCP数据

    tcpserver.py文件,服务器端启动,监听用户端发起的连接
    tcpclient.py文件,用户端启动,发起对服务器的连接
    连接之后相互之间可以通话,但同一时间只能保证一条连接
    当还有其他用户连接时只能等待,当前一个用户断开连接之后,下一个用户才能继续连接。

    #tcpserver.py
    import sys
    import os
    from socket import *
    import time
    import random
    
    HOST='127.0.0.1'
    
    RSIZE=1024
    
    class TCPServer:#非多线程,只能响应一个client
        
        def __init__(self,port,maxconnections=5):
            self._port=port
            self._maxconnections=maxconnections
            self._server=socket(AF_INET, SOCK_STREAM)
        
        def start(self):
            self._server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
            self._server.bind((HOST,self._port))
            self._server.listen(self._maxconnections)
            print("SERVER is listening on %s" % self._port)
            while True:#如果有多个client同是发起连接,只响应一个,其他会等待
                conn,addr=self._server.accept()#block
                print(f"client's connection: {conn}, its address:{addr}")
                while True:
                    try:
                        data=conn.recv(RSIZE)
                        if not data:
                            break
                        print("CLIENT: %s" % data.decode('utf-8'))
                        if data.decode('utf-8')=='bye':
                            conn.send("再见!".encode('utf-8'))
                            break
                        else:
                            conn.send('收到!'.encode('utf-8'))
                    except Exception as e:
                        print("SERVER ERROR: %s" % e)
                        break
                conn.close()
            self._server.close()
    
    def main():
        ser=TCPServer(int(sys.argv[1]))
        #ser = TCPServer(2021)
        ser.start()
    
    if __name__=='__main__':
        main()
    
    #tcpclient.py
    import os
    import sys
    import time
    import random
    from socket import *
    
    from tcpserver import TCPServer
    
    class TCPClient:
        def __init__(self,server_ip,server_port):
            self._server_ip=server_ip
            self._server_port=server_port
            self._client=socket(AF_INET,SOCK_STREAM)
    
        def start(self):
            self._client.connect((self._server_ip,self._server_port))
            while True:
                msg=input("CLIENT:")
                self._client.send(msg.encode('utf-8'))
                data=self._client.recv(1024)
                if not data:
                    continue
                if(data.decode('utf-8')=='再见'):
                    print("结束连接")
                    break
                else:
                    print("SERVER: %s" % data.decode('utf-8'))
            self._client.close()
    
    def main():
        client=TCPClient(sys.argv[1],int(sys.argv[2]))
        #client = TCPClient('127.0.0.1',2021)
        client.start()
    
    if __name__=='__main__':
        main()
    



    使用多线程模拟多人聊天

    #mtserver.py
    import sys
    import os
    from threading import Thread
    from socket import *
    
    BUFFERS=1024
    MAXC=64
    
    def speak(name,conn):
        print("欢迎{}进入聊天室...".format(name))
        while True:
            try:
                msg=conn.recv(BUFFERS)
                if not msg:
                    break
                print("{}:{}".format(name,msg.decode('utf-8')))
                if msg.decode('utf-8')=='byebye':
                    print("{}离开了聊天室...".format(name))
                    break
            except Exception as e:
                print("server error %s" % e)
                break
        conn.close()
    
    if __name__=='__main__':
        ip=sys.argv[1]
        port=int(sys.argv[2])
        server=socket(AF_INET,SOCK_STREAM)
        server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
        server.bind((ip,port))
        server.listen(MAXC)
        print("MT server is started...")
        while True:
            conn,addr=server.accept()#block
            ci,cp=addr
            #启动一个线程处理该连接,主线程继续处理其他连接
            t=Thread(target=speak,args=("client-"+ci+"-"+str(cp),conn))
            t.start()
        server.close()
    
    #mtclient.py
    import sys
    from socket import *
    from threading import Thread
    import random
    import time
    
    CHARS='abcdefghijklmnopqrstuvwxyz'
    ROUND=8
    
    class ChatBot(Thread):
        
        def __init__(self,ip,port,mlength):
            super().__init__()
            self._ip=ip
            self._port=port
            self._max_msg_length=mlength
    
        def _random_message(self):
            message=[]
            for i in range(self._max_msg_length):
                word=[]
                for j in range(random.randint(1,5)):
                    word.append(random.choice(CHARS))
                message.append(''.join(word))
            return ' '.join(message)
        
        def run(self):
            _client=socket(AF_INET,SOCK_STREAM)
            _client.connect((self._ip,self._port))
            _sent_count=0
            while True:
                msg=self._random_message()
                _client.send(msg.encode('utf-8'))
                _sent_count+=1
                time.sleep(random.randint(1,5))
                if _sent_count>ROUND:
                    _client.send('byebye'.encode('utf-8'))
                    break
            _client.close()
    
    def main():
        ip=sys.argv[1]
        port=int(sys.argv[2])
        tlist=[]
        for i in range(int(sys.argv[3])):
            tlist.append(ChatBot(ip,port,random.randint(4,8)))
        for t in tlist:
            t.start()
        for t in tlist:
            t.join()
        print("All bots exit...")
    
    if __name__=='__main__':
        main()
    

    在同一个程序里面同时实现server和client的功能,需要多加一个参数指定是server还是client。

    #schat.py
    from socket import *
    from threading import Thread
    import sys
    
    BS=2048
    
    def recv(name,conn):
        while True:
            data=conn.recv(BS)
            if not data:
                break
            if data.decode('utf-8')=='BYEBYE':
                print("对方提议停止聊天,输入BYEBYE可终止...")
                break
            else:
                print("%s: %s" % (name,data.decode('utf-8')))
    
    def send(conn):
        while True:
            msg=input("")
            if not msg:
                continue
            conn.send(msg.encode('utf-8'))
            if msg=='BYEBYE':
                break
    
    if __name__=='__main__':
        if len(sys.argv)!=4:
            print('usage: python schat.py ip port server|client')
        else:
            ip=sys.argv[1]
            port=int(sys.argv[2])
            name=sys.argv[3]#server, client
            server=socket(AF_INET,SOCK_STREAM)
            if name=='server':
                server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
                server.bind((ip,port))
                server.listen(5)
                print("server started...")
                conn,addr=server.accept()
            if name=='client':
                server.connect((ip,port))
                print('client connected...')
                addr=(ip,port)
                conn=server
            tr=Thread(target=recv,args=(str(addr),conn))
            tr.start()
            ts=Thread(target=send,args=(conn,))
            ts.start()
            tr.join()
            ts.join()
            conn.close()
            server.close()
    

    HTTP

    http.server

    – Defines classes for implementing HTTP servers (Web
    servers)
    HttpServer/ThreadingHttpServer: creates and listens at the HTTP socket, dispatching the requests to a handler
    • Handler: BaseHTTPRequestHandler,
    SimpleHTTPRequestHandler

    http.client

    – Defines classes which implement the client side of the HTTP and HTTPS protocols
    – It is normally not used directly
    urllib.request uses it to handle URLs that use HTTP and HTTPS

    UDP的优势

    • 应用层能更好地控制要发送的数据和发送时间
    • 无需连接建立
    • 不需要任何准备即可进行数据传输
    • 不引入建立连接的时延
    • 无连接状态
    • 无需维护一些状态参数
    • 分组头部开销小,TCP头至少占20字节,UDP头占8个字节
    #udpserver.py
    import sys
    import os
    from socket import *
    import time
    import random
    
    HOST='127.0.0.1'
    
    RSIZE=1024
    
    class TCPServer:#非多线程,只能响应一个client
        
        def __init__(self,port,maxconnections=5):
            self._port=port
            self._maxconnections=maxconnections
            self._server=socket(AF_INET, SOCK_STREAM)
        
        def start(self):
            self._server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口释放后马上可以被重新使用
            self._server.bind((HOST,self._port))
            self._server.listen(self._maxconnections)
            print("SERVER is listening on %s" % self._port)
            while True:#如果有多个client同是发起连接,只响应一个,其他会等待
                conn,addr=self._server.accept()#block
                print(f"client's connection: {conn}, its address:{addr}")
                while True:
                    try:
                        data=conn.recv(RSIZE)
                        if not data:
                            break
                        print("CLIENT: %s" % data.decode('utf-8'))
                        if data.decode('utf-8')=='bye':
                            conn.send("再见!".encode('utf-8'))
                            break
                        else:
                            conn.send('收到!'.encode('utf-8'))
                    except Exception as e:
                        print("SERVER ERROR: %s" % e)
                        break
                conn.close()
            self._server.close()
    
    def main():
        ser=TCPServer(int(sys.argv[1]))
        #ser = TCPServer(2021)
        ser.start()
    
    if __name__=='__main__':
        main()
    
    #udpclient.py
    import os
    import sys
    import time
    import random
    from socket import *
    
    from tcpserver import TCPServer
    
    class TCPClient:
        def __init__(self,server_ip,server_port):
            self._server_ip=server_ip
            self._server_port=server_port
            self._client=socket(AF_INET,SOCK_STREAM)
    
        def start(self):
            self._client.connect((self._server_ip,self._server_port))
            while True:
                msg=input("CLIENT:")
                self._client.send(msg.encode('utf-8'))
                data=self._client.recv(1024)
                if not data:
                    continue
                if(data.decode('utf-8')=='再见'):
                    print("结束连接")
                    break
                else:
                    print("SERVER: %s" % data.decode('utf-8'))
            self._client.close()
    
    def main():
        client=TCPClient(sys.argv[1],int(sys.argv[2]))
        #client = TCPClient('127.0.0.1',2021)
        client.start()
    
    if __name__=='__main__':
        main()
    

    SMTP

    • Simple Mail Transfer Protocol
    • 从发送方的邮件服务器向接收方的邮件服务器发送邮件
    • 运行在发送方邮件服务器的客户机端和接收方邮件服务器的服务器端
    • MIME:多用途互联网邮件扩展

    POP3

    • 与服务器建立连接(默认是110端口)
    • 认证——事务处理——更新
    • 未给用户提供任何创建远程文件夹以及为报文指派文件夹的方法

    IMAP

    • 互联网邮件访问协议
    • 创建文件夹并在文件夹之间移动邮件
    • 允许只读取报文头部

    相关文章

      网友评论

        本文标题:python网络编程

        本文链接:https://www.haomeiwen.com/subject/mjgrfrtx.html