网络编程(五)

前言

在上一篇文章中咱们学习了 基于 TCP 套接字的服务端和客户端通讯,并解决了粘包的问题,解决粘包问题的思路很简单,就是确保接受方可以把数据收取干净,发多少,就收多少.python

出现粘包的问题:缘由有两个,一个是接收数据量少于发送数据量;一个是由于为了优化 TCP 的传输效率,使用了 Nagle算法,当客户端连续发送时间间隔很短的两个数据包时,在未确认数据发送的时候让发送器把数据送到系统缓存里.任何数据随后继续直到获得明显的数据确认或者直到攒到了必定数量的数据了再发包.算法

这是不可避免的,为了优化传输效率,尽可能发送大块数据,避免网络中充斥的许多小数据块.知道了解决方法,那么避免粘包就很简单了,只须要在每次发送数据以前先发送真实数据的长度,而后接收方能够根据收到的真实长度收取数据了.编程

SOCKET使用

SOCKET AF_INET套接字主要有两种协议,如今来看 UDP 协议是如何进行网络通讯的.缓存

基于 UDP 链接的套接字

tcp 是无链接,不稳点的套接字,可是传输效率较高,因此在某些应用上如实时直播,游戏, DNS 服务器,DHCP 服务器等等.服务器

服务端网络

from socket import *

serverSock = socket(AF_INET, SOCK_DGRAM)
serverSock.bind(('', 8080))

while True:
    data, client_addr = serverSock.recvfrom(1024)
    print(data)
    serverSock.sendto(data.upper, client_addr)
serverSock.close()

客户端并发

from socket import *

clientSock = socket(AF_INET, SOCK_DGRAM)

while True:
    msg = input('>>>').strip()
    clientSock.sendto(msg.encode('utf-8'), ('', 8080))
    data, server_addr = clientSock.recvfrom(1024)
    print(data)

当咱们连续开多个客户端和服务端通讯的时候,没有出现阻塞的状况,发出去的消息均可以收回来,这是由于 udp 是无链接的套接字,不用关注一个链接,只要你给我发消息拿到了发送方的 ip 和端口,那么就能够直接和你通讯,并且不像 TCP 那样必须先启动服务端才能够, udp 在发送数据的时候,服务端没有启动也能够发送过去,只不过是发到了对方的系统缓存中.socket

那么 udp 能够实现多个客户端同时和客户端通讯吗?tcp

以前几个客户端能够同时和服务端通讯是由于服务端的处理能力很大,看起来是同时通讯同样,可是若是把客户端加到 1w, 甚至更多就会感受到明显的时间差了.学习

那么如何能够实现真正的并发呢?关键点就在一个通讯循环和链接循环互相不干扰,不用由于 i/o 堵塞而耽搁另外一个循环要作的事.

Socketserver 模块实现并发

在这里 python 有一个模块为 socketserver 能够实现真正的并发.

基于 TCP 协议的并发

服务端

import sockerserver

class MyTCPhandler(socketserver.BaseRequestHandler):
    def handler(self):
        while True:
            try:
                data = self.request.recv(1024)
                if len(data) == 0:
                    break
                print('-->收到客户端的消息:', data)
                self.request.send(data.upper())
            except ConnectResetError:
                break
        self.request.close()
        
if __name__ == '__main__':
    serverSock = socketserver.ThreadingTCPServer(('127.0.0.1', 8081), MyTCPhandler)
    serverSock.serve_forever() # 和客户端进行链接

客户端

from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8081))

# 通讯循环
while True:
    clientSock.send(b'hello')
    data = clientSock.recv(1024)
    print(data)
    
clientSock.close()

这样就解决了 TCP 不能实现并发的问题了.

基于 UDP 协议的并发

服务端

import socketserver

class MyUDPhandler(socketserver.BaseRequestHandler):
    def handler(self):
        data, serverSock = self.request
        serverSock.sendto(data.upper(), self.client_address)
        
if __name__ == '__main__':
    server = socketserver.ThreadingUDPServer(('127.0.0.1', 8081), MyUDPhandler)
    server.serve_forever()

客户端

from socket import *

clientSock = socket(AF_INET, SOCK_DGRAM)

while True:
    clientSock.sendto(b'hello', ('127.0.0.1', 8081))
    data, server_addr = client.recvfrom(1024)
    print(data)

这就是 UDP 实现并发的模板.

总结

到此,网络编程终于告一段落了,其实我写的是网络编程里面极少的也是较为重要的一部分,还有不少底层协议没了解,像 ping 服务器时发送的 ICMP 包,还有不少,不过我以为了解了这些其实也就了解了互联网工做的基本方式,其他的待有时间了再来学习.

若有不对的地方,欢迎指正.

相关文章
相关标签/搜索