Python之socket
Socket通长也称作"套接字",用于描述IP地址和端口,是一个通信的句柄.
vim day8-16.py
#!/usr/bin/env python
#coding:utf-8
import socket
def handle_request(client):
buf = client.recv(1024)
print buf
client.send("HTTP/1.1 200 OK\r\n\r\n")
client.send("Hello, World")
def main():
#创建socket对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#bind方法监听某个端口
sock.bind(('127.0.0.1',8080))
#开始监听,
sock.listen(5)
while True:
#阻塞,等...
#直到有请求连接
connection, address = sock.accept()
#connection代表客户端sockert对象
#address客户端IP地址
handle_request(connection)
connection.close()
if __name__ == '__main__':
main()
运行,然后在开启一个客户端访问

本客户端返回

使用python建立一个socket的服务端和客户端
vim socket_server.py
#!/usr/bin/env python
#coding:utf-8
import socket
obj_server = socket.socket()
obj_server.bind(('localhost',8341))
obj_server.listen(5) #开始监听最大连接数5
while True:
print 'waiting...'
conn,addr = obj_server.accept()
client_data = conn.recv(1024) #最多一次性接收1024size
print client_data
conn.send('好的')
conn.close()
vim socket_client.py
#!/usr/bin/env python
#coding:utf-8
import socket
obj = socket.socket()
obj.connect(('localhost',8341))
obj.send('我爱北京天安门')
server_data = obj.recv(1024)
print server_data
obj.close()
~
运行服务端,然后新开一个窗口运行客户端


智能机器人实例
vim day8-18.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
while True:
conn,address = sk.accept()
conn.sendall('欢迎致电10086,请输入1xxx,0转人工服务')
Flag = True
while Flag:
data = conn.recv(1024) #阻塞等待客户端发生数据
print data #打印从客户端接收到的数据
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('您的通话可能被录音')
else:
conn.sendall('请重新输入')
conn.close()
vim day8-19.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.connect(ip_port) #客户端连接服务端
sk.settimeout(5)
while True:
data = sk.recv(1024) #接收服务端数据欢迎致电...
print 'recevie:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break
sk.close()
执行过程
服务端

客户端

PS:一个socket同时只能处理一个请求,如果一个请求在连接中,其他请求在过来将排队等待,等待时间为设置的超时时间为5s,python提供了一个模块用于多线程模块socketserver
SoketServer
多线程条件
1,必须写一个类
2,必须继承SocketServer.BaseRequestHandler
3,必须写一个方法而且方法名必须为handle
4,必须调用ThreadingTCPServer方法来实现多线程
day8-22.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
import os
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
print "--got connection from", self.client_address
while True:
data = self.request.recv(1024)
print "Recv from cmd:%s" %(data)
cmd_res = os.popen(data).read()
print 'cmd_res:',len(cmd_res) #打印服务器发送数据长度
self.request.sendall(cmd_res)
if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever() #永久运行
客户端vim day8-23.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)
while True:
# data = sk.recv(1024)
# print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
while True:
data = sk.recv(1024)
print "---data---"
# if len(data) == 0:
if len(data) < 1024:
print '---not data---'
break
print data
if inp == 'exit':
break
sk.close()
客户端输入命令服务端把命令结果返回给客户端打印
修改代码让服务器在发送数据之前就把要发送的大小发送给客户端,客户端根据包的大小进行判断打印
服务端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
import os
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
print "--got connection from", self.client_address
while True:
data = self.request.recv(1024)
print "Recv from cmd:%s" %(data)
cmd_res = os.popen(data).read()
print 'cmd_res:',len(cmd_res) #打印服务器发送数据长度
self.request.send( str(len(cmd_res)) ) #服务端要给客户端发多长数据
self.request.sendall(cmd_res)
if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever() #永久运行
客户端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)
while True:
# data = sk.recv(1024)
# print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
res_size = sk.recv(1024)
print "goint to recv data size:",res_size,type(res_size)#打印将收到多少数据和数据类型
total_size = int(res_size) #共要收取的
received_size = 0
while True:
data = sk.recv(1024)
received_size += len(data)
print "---data---"
# if len(data) == 0:
# if len(data) < 1024:
if total_size == received_size: #如果收到的大小等于收到的大小代表收完了
print data
print '---not data---'
break
print data
if inp == 'exit':
break
sk.close()
PS:这样也会出现问题,这两个包可能在网络层集合成一个包发送给客户端导致客户端接收ValueError,这种现象叫连包,可以通过修改服务器端代码(比如两个包之间sleep1秒再发送下一个包),但是效率太低

可以通过在两条消息直接加代码解决
服务端

客户端回一条可以是一个空格

作业:客户端往服务端发文件,客户端可以从服务端下载文件,实现文件MD5验证和用户验证

浙公网安备 33010602011771号