您的位置:首页 > 理论基础 > 计算机网络

Python:网络编程

2016-06-11 18:47 741 查看

socket介绍

socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

socket和file的区别:

file模块是针对某个指定文件进行【打开】【读写】【关闭】

socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

import socket

ip_port = ('127.0.0.1',8005)
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)
if inp == 'exit':
break

sk.close()


客户端

基于socket实现文件上传

服务端:

import socket
sk = socket.socket()
sk.bind(("127.0.0.1",9990,))
sk.listen(2)

while True:
conn,adress = sk.accept()
conn.sendall(bytes("Hello",encoding="utf-8"))

f_size = str(conn.recv(1024),encoding="utf-8")
conn.sendall(bytes("ok",encoding="utf-8"))

#接收文件
total_size = int(f_size)
has_size = 0
f = open("new.png","wb")
while True:
if total_size == has_size:
break
else:
ret = conn.recv(1024)
f.write(ret)
has_size += len(ret)
f.close()


客户端:

import socket
import os

obj = socket.socket()
obj.connect(("127.0.0.1",9990))

obj_str = str(obj.recv(1024),encoding="utf-8")
print(obj_str)

#发送文件大小
file_size = os.stat("XX.png").st_size
obj.sendall(bytes(str(file_size),encoding="utf-8"))
ret = str(obj.recv(1024),encoding="utf-8")
print(ret)

#发送文件
with open("XX.png","rb") as f:
for line in f:
obj.sendall(line)

obj.close()


并发操作:

可以通过IO多路复用,也可以通过socketserver来实现。

socketsercver内部是基于IO多路复用多线程来实现多并发操作

socketserver模块实现并发操作:

服务端:

import socketserver

class MyServer(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
conn.sendall(bytes("Hello", encoding="utf-8"))  # 向客户端发送内容
while True:
conn_bytes = conn.recv(1024)
conn_str = str(conn_bytes,encoding="utf-8")
if conn_str == "q":
break
conn.sendall(bytes(conn_str + "ok",encoding="utf-8"))

if __name__ == "__main__":
sever = socketserver.ThreadingTCPServer(("127.0.0.1", 8888), MyServer)
sever.serve_forever()


注:

1、socketserver可并发处理多个客户端请求

2、使用时创建类,必须继承

3、类里面必须有handle方法

4、把类当做参数传到对象里面,然后执行server_forever

IO多路复用

  I/O多路复用指:通过一种机制,可以监视多个描述符。一旦某个描述符就绪(一般是读就绪或者写就绪),就能够通知程序进行相应的读写操作。

  Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用

import socket

sk1 = socket.socket()
sk1.bind(("127.0.0.1",8001,))
sk1.listen(5)

sk2 = socket.socket()
sk2.bind(("127.0.0.1",8002,))
sk2.listen(5)

inp = [sk1,sk2]
import select
while True:
#[sk1,sk2],select内部自动监听sk1,sk2两个对象,一旦某个句柄发生变化
#如果有人连接sk1==>r_list = [sk1]
r_list,w_list,e_list = select.select(inp,[],[],1)
for sk in r_list:
#每一个连接对象
conn,adress = sk.accept()
conn.sendall(bytes("Hello",encoding="utf-8"))
conn.close()


参数说明:

r_list:如果有人连接sk1 or sk2...,就将sk1 or sk2添加到里面

w_list:将客户端发送给服务端的客户端对象添加到里面

e_list:监听出现错误的文件句柄,将错误的放到里面

2:最多等待的时间:select是检测句柄变化的,2表示用2秒检测是否发生变化

import socket
sk1 = socket.socket()
sk1.bind(("127.0.0.1",8005,))
sk1.listen(5)

inp = [sk1]
outputs = [] # 哪个客户端发来消息就基类哪个客户端
message_dict = {} # 客户端对应的发送的消息

import select
while True:
r_list,w_list,e_list = select.select(inp,outputs,inp,2)
print("正在监听的socket对象%d" % len(inp))
print(r_list)
for sk1_or_conn in r_list:
#每连接一个对象
if sk1_or_conn == sk1:
#表示有新用户来连接
conn,adress = sk1_or_conn.accept()
inp.append(conn)
message_dict[conn] = []
else:
try:
sk1_bytes = sk1_or_conn.recv(1024)
# sk1_str = str(sk1_bytes,encoding="utf-8")
# sk1_or_conn.sendall(bytes(sk1_str + "ok",encoding="utf-8"))
except Exception as ex:
inp.remove(sk1_or_conn)
else:
sk1_str = str(sk1_bytes,encoding="utf-8")
message_dict[sk1_or_conn].append(sk1_str)
for conn in w_list:
recv_str = message_dict[conn][0]
del message_dict[conn][0]
conn.sendall(bytes(recv_str + "ok",encoding="utf-8"))
outputs.remove(conn)

for sk in e_list:
inp.remove(sk)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: