python网络编程

介绍

计算机网络就是把各个计算机连接在一起,让网络中的计算机可以互相通信,网络编程就是如何在程序中实现两台计算机的通信。
网络通信就是两个进程之间在通信。

OSI七层模型 —》 网络通信工作流程的标准化
应用层 : 提供用户服务,具体功能由特定的程序而定。
表示层 : 数据的压缩优化,加密。
会话层 : 建立应用级的连接,选择传输服务。
传输层 : 提供不同的传输服务。流量控制。
网络层 : 路由选择,网络互连。
链路层 : 进行数据转换,具体消息的发送,链路连接。
物理层 : 物理硬件,接口设定,网卡路由交换机等。

优点
1.将工作流程标准化。
2.降低了模块间的耦合度,使每一个部分可以单独开发,单独工作。

计算机为了联网,就必须规定通讯协议,为了全世界的的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议。互联网协议簇(Internet Protocol Suite)就是通用协议标准。任何私有网络,只要支持这个协议,就可以联入互联网。
互联网中包含上百种协议标准,但最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称为TCP/IP协议。
通信的时候,双方必须知道对方的标识,好比发送邮件必须知道对方的邮件地址。互联网上每个计算机的唯一标识就是IP地址。如果一台计算机同时接入到两个或更多的网络,比如路由器,它就会有两个或多个IP地址,所以,IP地址对应的实际上是计算机的网络接口,通常是网卡。
IP协议负责把数据从一台计算机通过网络发送到另一台计算机上。数据被分割成一小块一小块,然后通过IP包发送出去。
TCP协议则是建立在IP协议基础上的,TCP协议负责在两台计算机之间建立可靠的连接,保证数据包按顺序到达,TCP协议会通过建立握手连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。
许多更高级的协议都是建立在TCP协议的基础上的,比如用于浏览器的HTTP协议,发送邮件的SMTP协议等。
一个TCP报文除了包含要传输的数据外,还包含源IP地址和目标IP地址,源端口和目标端口。

端口有什么作用?在两台计算机通信时,只发IP地址是不够的,因为同一台电脑上跑着多个网络程序,一个TCP报文来了之后,到底交给浏览器还是QQ,就需要端口来区分,每个网络程序都向操作系统申请一个唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号了。

TCP编程

socket是网络编程的一个抽象概念,通常我们用一个socket表示打开一个网络链接,而打开一个socket需要知道目标计算机的IP地址和端口号,在指定协议类型即可。

客户端

大多数连接都是可靠的TCP连接,创建TCP连接时,主动发起连接的是客户端,被动响应的叫服务器。
创建一个基于TCP连接的socket,可以这样做:

#导入socket库
import socket

#创建一个socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立连接
s.connect(('www.baidu.com',80))

AF_INET:指定使用IPv4协议,如果使用IPv6,就指定AF_INET6。
SOCT_STREAM:指定面向流的TCP协议。
以上一个socket创建成功。
创建连接代码如下:

s.connect(('www.baidu.com',80))

注意:参数是一个tuple,包含地址和端口。
建立连接之后,可以发送信息到百度。

#发送数据
data = input("发送>>")
s.send(data.encode())

TCP连接创建的是双向通道,双发都可以同时给对方发送信息。谁先发谁后发,这是由协议协调处理的,比如HTTP协议规定客户端必须先发送请求给服务器,服务器收到之后才发数据给客户端。

#接收数据
buffer = []
while True:
    #每次最多接收1k字节
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)

接收数据时,调用recv(max)方法,一次最多接收指定的字节数,因此。在一个while循环反复接收,直到recv()返回空数据,表示接收完毕,退出循环

接收完数据之后,调用close()方法关闭Socket,这样,一次完整的通信就结束了。

#关闭连接
s.close()
服务器

服务器编程比客户端编程较为复杂。
服务器进程首先要绑定一个端口并监听来自其他客户端的连接,如果某个客户端连接过来了,服务器就和改客户端建立socket连接,随后的通信就靠这个socket连接了。
一个socket依赖4项:服务器地址,服务器端口,客户端地址,客户端端口来确定唯一一个socket。
服务器还需要同时响应多个客户端的请求,所以,每个连接都需要一个新的进程或者新的线程来处理,否则,服务器一次就只能服务一个客户端了。
首先,创建一个基于IPv4和TCP协议的Socket:

s = socket.socket(socket.AF_INEF,socket.SOCK_STREAM)

然而,我们要绑定监听的地址和端口,服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以绑定所有的网络地址,还可以绑定本机的网络地址。
端口号需要预先指定,一般自定义的端口号 1024 —65535。

#监听端口
s.bind(('127.0.0.1',9999))

紧接着,调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量。

s.listen(5)
print('Waiting for connection...')

接下来,服务器程序通过一个永久循环来接受来自客户端的连接,accept()会等待并返回一个客户端的连接。

while True:
    #接受一个新连接
    sock,addr = s.accept()
    #创建新线程来处理TCP连接
    t = threading.Thread(target=tcplink,args=(sock,addr))
    t.start()

每个连接都必须新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接:

def tcplink(sock,addr):
    print('Accept new connection from %s:%s...'% addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send('Hello,%s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)

上面的连接建立之后,服务器首先会发送一条欢迎信息,然后等待客户端数据,并加上Hello再发送给客户端,如果客户端发送了exit字符串,就直接关闭连接。
测试该程序的代码,需要编写一个客户端程序:

s = socket.socket(socket.AF_INEF,socket.SOCK_STREAM)
#建立连接:
s.connect(('127.0.0.1',9999))
#接收欢迎信息
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael',b'Tracy',b'Sarah']:
    #发送数据:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

用TCP协议进行Socket编程在python中十分简单,对于客户端,要主动连接服务器的IP和端口号,对于服务器,要首先监听指定端口,然后,对每一个新的连接,创建一个线程进程来处理,通常,服务器程序会无限运行下去。

UDP编程

使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以发送数据包。但是,是不稳定可靠的,能不能到达就不知道了。
虽然UDP传输数据不可靠,但是它的优点就是比TCP的速度快,对于不要求可靠到达的数据,就可以使用UDP协议。
UDP服务端:

s = socket.socket(socket.AF_INEF,socket.SOCK_DGRAM)
#绑定端口
s.bind(('127.0.0.1',9999))

SOCK_DGRAM:指定这个socket的类型是UDP。绑定端口和TCP一样,但是不需要调用listen()方法。而是直接接收来自任何客户端的数据:

print('Bind UDP on 9999....')
while True:
    #接收数据:
    data,addr = s.recvfrom(1024)
    print('Received from %s:%s' % addr)
    s.sendto(b'Hello, %s!' % data,addr)

recvfrom()方法返回数据和客户端的地址和端口,这样,服务器收到数据后,直接调用sendto()就可以把数据用UDP发给客户端。

以下为客户端使用UDP给服务器发送并接收数据:

s = socket.socket(socket.AF_INEF,socket.SOCK_DGRAM)
for data in [b'Micheal',b'Tracy',b'Sarah']:
    #发送数据
    s.sendto(data,('127.0.0.1',9999))
    #接收数据
    print(s.recv(1024).decode('utf-8'))
s.close()

UDP和TCP使用类似,但是不需要建立连接,此外,服务器绑定的UDP端口和TCP端口互不冲突,也就是说,UDP的9999端口和TCP的9999端口可以各自绑定。

TCP套接字编程和UDP套接字编程的区别
1.流式套接字使用字节流的方式传输,数据报套接字以数据报形式传输数据
2.tcp会有粘包现象,udp有消息边界不会产生粘包。
3.tcp可以保证数据传输完整性,udp则不会。
4.tcp需要connect,accept 操作,udp不需要。

黄沙百战穿金甲,不破楼兰终不还

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值