网络通信是两台计算机上的两个进程之间的通信
一、TCP编程
服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Socket连接了。
服务器会打开固定端口(比如80)监听,每来一个客户端连接,就创建该Socket连接,一个Socket依赖4项:
服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket。
客户端发起tcp连接
import socket import ssl s=ssl.wrap_socket(socket.socket()) #建立连接: s.connect(('www.sina.com.cn',443)) #发送数据: s.send(b'GET/HTTP/1.1\r\nHost:www.sina.com.cn\r\nConnection:close\r\n\r\n') # 接收数据: buffer = [] while True: # 每次最多接收1k字节: d = s.recv(1024) if d: buffer.append(d) else: break data = b''.join(buffer) #关闭连接: s.close() header, html = data.split(b'\r\n\r\n', 1) print(header.decode('utf-8')) # 把接收的数据写入文件: with open('try.html', 'wb') as f: f.write(html)
服务器:
import socket,threading,time #AF_INET指定使用IPv4协议、SOCK_STREAM指定使用面向流的TCP协议 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #监听端口: s.bind(('127.0.0.1',1056)) #调用listen()方法开始监听端口,传入参数指定等待连接的最大数量: s.listen(5) print("waiting for connection...") #每个连接都必须创建新线程来处理,否则无法接收其他客户端的连接: 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) #如果数据流为空,或者客户端发送来exit信息则退出连接 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) # 通过一个永久循环来接收客户端的连接、accept()会等待并返回一个客户端的连接: while True: #一直处在监听状态 sock,addr=s.accept() #返回新网络连接tcp,客户端ip地址 #创建线程进程操作tcp t=threading.Thread(target=tcplink,args=(sock,addr)) #启动线程 t.start()
客户端:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立连接: s.connect(('127.0.0.1', 1056)) # 接收欢迎消息: 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()
Web服务标准端口是80,SMTP服务是25端口,FTP服务是21端口,端口号小于1024的是Internet标准服务的端口,端口号大于1024的可以任意使用。
要绑定监听的地址和端口。服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址。
127.0.0.1是一个特殊的IP地址,表示本机地址,如果绑定到这个地址,客户端必须同时在本机运行才能连接,也就是说,外部的计算机无法连接进来。
二、UDP编程
TCP建立可靠连接,并且通信双方都可以以流的形式发送数据。
UDP协议不需要建立连接,传输数据不可靠,但速度快。
UDP的通信双方也分为客户端和服务器:
服务器:
import socket #SOCK_DGRAM指定scoket类型是UDP s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定端口: s.bind(('127.0.0.1', 9999)) print('Bind UDP on 9999...') #不需要调用listen()方法,直接接收来自任何客户端的数据: while True: # 接收数据: data, addr = s.recvfrom(1024) #返回客户端地址与接口 print('Received from %s:%s.' % addr) s.sendto(b'Hello, %s!' % data, addr) #服务器接到数据后,调用sendto()可以把数据发给客户端
客户端:
import socket #不需要调用connect(),直接通过sendto()给服务器发数据: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for data in [b'Michael', b'Tracy', b'Sarah']: # 发送数据: s.sendto(data, ('127.0.0.1', 9999)) # 接收数据: print(s.recv(1024).decode('utf-8')) s.close()
服务器绑定UDP端口和TCP端口互不冲突。
【本博客中Python基础笔记均是在廖雪峰的官方网站学习过程中记录的,仅作参考】