知识内容:
1.socket语法及相关
2.黏包
3.struct模块
4.subprocess模块
5.socketserver模块
6.验证客户端连接的合法性
参考:
http://www.cnblogs.com/Eva-J/articles/8244551.html
http://www.cnblogs.com/alex3714/articles/5227251.html
关于网络基础概念:http://www.cnblogs.com/wyb666/p/9014857.html
一、socket语法及相关
1.基于TCP协议的socket
TCP是基于连接的,必须先启动服务端,然后再启动客户端去链接服务端;另外双方一定要有一方发消息一方收消息,不能同时收消息或同时发消息
TCP编程中用到的socket模块中的方法如下:
- socket([family, [, type, [proto]]]): 创建一个socket对象
- connect(address): 连接远程主机
- send(bytes[, flags]): 发送数据
- recv(bufsize[, flags]): 接受数据
- bind(address): 绑定地址
- listen(backlog): 开始监听,等待客户端连接
- accept(): 响应客户端的请求
- close(): 关闭连接或关闭服务器
server.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 4 import socket # 导入socket模块 5 sk = socket.socket() 6 sk.bind(('127.0.0.1', 8888)) # bind(('ip', 'port')) 绑定ip和端口号 7 sk.listen() # 监听连接 8 9 conn, addr = sk.accept() # 接收客户端连接 10 11 res = conn.recv(1024) # 接收信息 12 print(res) 13 conn.send(b'hi!') # 发送信息,必须传一个bytes类型 14 res = conn.recv(1024) 15 print(res.decode('utf-8')) # 解码 16 conn.send(bytes("吃包子啊!".encode('utf-8'))) # 编码 17 18 conn.close() # 关闭连接 19 sk.close() # 关闭服务器 20 21 22 # 有收必有发,收发必相等
client.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import socket 4 5 sk = socket.socket() 6 7 sk.connect(('127.0.0.1', 8888)) # 连接服务器 8 sk.send(b'wyb') # 发送信息 9 res = sk.recv(1024) # 接受信息 10 print(res) 11 sk.send(bytes("中午吃什么".encode('utf-8'))) # 编码 12 res = sk.recv(1024) 13 print(res.decode("utf-8")) # 解码 14 15 sk.close() # 关闭客户端
2.基于UDP协议的socket
udp是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接,而是直接向接收方发送信息
UDP编程中用到socket模块中的如下方法:
(1)socket([family, [, type, [proto]]]): 创建一个socket对象,参数如下:
- family为socket.AF_INET表示IPV4,family为socket.INET6表示IPV6
- type为SOCK_STREAM表示TCP,type为SOCK_DGRAM表示UDP
- proto为协议号,通常为零,可以省略
(2)sendto(string, address):把string指定的内容发送给address指定的地址,其中address是一个包含接受方主机IP地址和应用进程端口号的元组,
格式为(IP地址, 端口号)
(3)recvfrom(bufsize[, flags]):接受数据,bufsize是可接受的最大数据,单位为kb
(4)bind(address): 绑定地址
(5)close(): 关闭服务器
server.py
1 # __author__ = "wyb" 2 # date: 2018/5/9 3 import socket 4 5 sk = socket.socket(type=socket.SOCK_DGRAM) # DGRAM datagram 6 sk.bind(('127.0.0.1', 8888)) # '127.0.0.1', 8888 -> server端地址 7 8 msg, addr = sk.recvfrom(1024) # 接受消息 9 print(msg.decode("utf-8")) 10 sk.sendto(b"bye", addr) # 发送消息 addr -> client端地址 11 12 sk.close() 13 # UDP的server不需要进行监听,也不需要建立连接,在启动服务之后只能被动的等 14 # 客户端发送消息过来,客户端发送消息的同时还会自带地址信息 15 # 消息回复的时候,不仅需要发送消息也要填上对方的地址
client.py
1 # __author__ = "wyb" 2 # date: 2018/5/9 3 import socket 4 5 sk = socket.socket(type=socket.SOCK_DGRAM) # DGRAM datagram 6 7 ip_port = ('127.0.0.1', 8888) # 发送的地址 '127.0.0.1', 8888 -> server端地址 8 9 sk.sendto(b"hello", ip_port) # 发送消息 10 ret, addr = sk.recvfrom(1024) # 接受消息 addr -> server端地址 11 print(ret.decode("utf-8")) 12 13 sk.close()
3.相关练习
(1)话痨对话
server.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import socket 4 5 sk = socket.socket() 6 7 sk.bind(('127.0.0.1', 8888)) 8 sk.listen() 9 10 conn, addr = sk.accept() 11 12 while True: 13 res = conn.recv(1024).decode('utf-8') # 接收消息(解码) 14 if res == "bye": # 退出 15 conn.send(b"bye") 16 break 17 print(res) # 输出消息 18 mes = input(">>>") # 输入消息 19 conn.send(mes.encode('utf-8')) # 发送消息(编码) 20 21 conn.close() 22 sk.close()
client.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import socket 4 5 sk = socket.socket() 6 7 sk.connect(('127.0.0.1', 8888)) 8 9 while True: 10 msg = input(">>>") # 输入消息 11 sk.send(msg.encode('utf-8')) # 传输消息(编码) 12 res = sk.recv(1024).decode("utf-8") # 接收消息(解码) 13 if res == 'bye': # 退出 14 sk.send(b'bye') 15 break 16 print(res) # 输出消息 17 18 sk.close()
(2)时间服务器
server.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import socket 4 from time import strftime 5 6 ip_port = ('127.0.0.1', 8888) # server端地址 7 8 udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 9 udp_server.bind(ip_port) 10 11 while True: 12 msg, addr = udp_server.recvfrom(1024) # 接受消息 13 print(msg.decode("utf-8")) 14 15 # 根据接受到的消息进行处理 16 if not msg: 17 time_fmt = '%Y-%m-%d %X' 18 else: 19 time_fmt = msg.decode('utf-8') 20 # 根据时间格式生成时间信息 21 back_msg = strftime(time_fmt) 22 23 # 发送消息 24 udp_server.sendto(back_msg.encode("utf-8"), addr) 25 26 27 udp_server.close()
client.py
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import socket 4 5 ip_port = ('127.0.0.1', 8888) 6 udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 8 while True: 9 msg = input('请输入时间格式(例%Y %m %d)>>: ').strip() # 输入信息 10 udp_client.sendto(msg.encode('utf-8'), ip_port) # 发送信息 11 12 data = udp_client.recv(1024) # 接受消息 13 print(data.decode("utf-8")) 14 15 16 udp_client.close()
(3)QQ聊天
server.py
1 import socket 2 3 ip_port = ('127.0.0.1', 8005) 4 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 sk.bind(ip_port) 6 7 while True: 8 data, addr = sk.recvfrom(1024) # 接受消息 9 if data == b"bye": 10 break 11 print(data.decode("utf-8")) 12 info = input(">>>").encode("utf-8") 13 sk.sendto(info, addr) 14 15 sk.close()
client.py
1 import socket 2 3 ip_port = ('127.0.0.1', 8005) 4 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 6 while True: 7 msg = input("老王: ") 8 msg = "