socket编程
一、server端和client端通过套接字互相通信(基于TCP)
1.对于服务器端的整个流程:
1.先创建套接字:sk = socket.socket()
2.设定ip和port,将套接字绑定在(ip,port)上:sk.bind((ip,port))
3.进行监听,并设定处理队列中最大的处理连接数:sk.listen(5)
4.进入while死循环
1.等待客户端连接服务器端的套接字并返回与客户端连接的套接字conn和ip+port
2.然后从调用conn.recv(1024)方法,通过套接字conn中接收数据并打印,1次性最大接收1024字节
3.调用conn.sendall(****)方法,通过套接字conn向客户端发送数据
4.调用conn.close()方法,关闭套接字
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
#定义主机的地址和端口号
ip_port = ('127.0.0.1',999)
#创建socket对象sk
sk =socket.socket()
#将socket绑定到127.0.0.1主机的999端口上
sk.bind(ip_port)
#将此连接套接字接口变成被连接套接字接口,即将此进程设置为服务器进程,可以接受其他请求。
# 5表示已完成服务器连接但服务器未处理的最大进程数量,即等候处理的连接
sk.listen(5)
#设定死循环
while True:
print "plz waiting...."
#调用套接字的accept函数接受客户端的主动连接,并返回2个信息:
# 1.连接至服务器的客户端的套接字conn
# 2.连接至服务器端的客户端的ip+port,并以元组的形式返回出来
conn,addr = sk.accept()
print addr
#从客户端套接字接收数据,并且每次只能接收最大1024字节
get_data = conn.recv(1024)
print get_data
#通过客户端套接字向客户端发送数据
conn.send("this is server,hello client")
#关闭套接字
conn.close()
2.客户端连接的整个流程
1.创建套接字对象
2.设置要连接的服务器端的ip和端口port,并调用sk.connect((ip,port))方法进行连接服务器
3.分别调用sendall()方法和recv()方法进行发送和接收数据
4.关闭套接字
import socket
#设定要连接的服务器的端口和IP
ip_port = ('127.0.0.1',999)
#创建socket对象sk
sk = socket.socket()
#调用sk.connect(ip_port)连接服务器端
sk.connect(ip_port)
#调用sk.sendall()方法向服务器端发送信息
sk.sendall('this is client,hello server')
#调用sk.recv(1024)方法接收服务器端发来的信息
server_reply = sk.recv(1024)
print server_reply
#关闭套接字
sk.close()
二、server端的WEB服务的代码(基于TCP)
server.py
#定义处理请求的函数,传入客户端的套接字
def handle_request(client):
get_data = client.recv(1024)
client.send("jachy")
client.send("HTTP/1.1 200 OK\r\n\r\n")
#定义主函数,用于服务器端的套接字的创建、监听、以及阻塞
def main():
import socket
sk = socket.socket()
ip_port = ('localhost',999)
sk.bind(ip_port)
sk.listen(5)
while True:
conn,addr = sk.accept()
#传入监听得到的套接字conn,然后传入请求处理函数,进行对请求进行处理
handle_request(conn)
conn.close()
if __name__ == "__main__":
main()
三、server端和client端通过套接字互相通信(基于UDP通信)
流程:
服务器端:
1.创建基于UDP通信的套接字sk
2.将套件字绑定在特定端口和IP上,调用sk.bind((ip,port)) 【不用像tcp通信一样进行监听,即调用sk.listen(5)】
3.创建while死循环,等待接收客户端发送的数据,直接调用sk.recv(1024)
4.关闭套接字
客户端:
1.创建基于UDP的套接字对象
2.向特定套接字发送数据,调用sk.sendto('数据',套接字)
3.关闭套接字
1.客户端的代码:client.py
import socket
ip_port = ('127.0.0.1',999)
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
while True:
inp = raw_input("data:").strip()
if inp == 'exit':
break
sk.sendto(inp,ip_port)
sk.close()
2.服务器端的代码
import socket
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
ip_port = ('127.0.0.1',999)
sk.bind(ip_port)
#sk.listen(5) #UDP不用监听套接字,否则会出错
while True:
data = sk.recv(1024)
print data
简版机器人示例
服务器端:对客户端发过来的信息进行判断,然后对不同的信息采取不同的处理方式
import socket
ip_port = ('127.0.0.1',1111)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
while True:
conn,addr = sk.accept()
conn.sendall('welcome to phone,0 to man ')
Flag = True
while Flag:
print 'plz waiting.....'
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('connect from man')
else:
conn.sendall('plz input again:')
conn.close()
客户端:(在客户端对输入的内容进行判断,当输入的是exit时,就自动关闭套接字连接)
import socket
ip_port = ('127.0.0.1',1111)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)
while True:
data = sk.recv(1024)
print "receieve :",data
inp = raw_input("plz input :").strip()
sk.sendall(inp)
if inp == "exit":
break
sk.close()
四、基于SocketServer多线程处理并发
server.py
import SocketServer
#定义MyServer类,继承BaseRequestHandler类,请求处理
class MyServer(SocketServer.BaseRequestHandler):
#定义处理对象函数
def handle(self):
#得到客户端的套接字conn
conn = self.request
#向客户端套接字发送信息
conn.sendall("welcome to phone 10086,0 to man ,1 to work")
#设定标志位,为当收到exit信息时,跳出循环做准备
Flag = True
while Flag:
data = conn.recv(1024)
if data == "exit":
Flag = False
elif data == "0":
conn.sendall("connect to people")
else:
conn.sendall("plz input again:")
if __name__ == "__main__":
ip_port = ('127.0.0.1',8009)
#传入特定地址的套接字和处理方法,创建多线程处理服务器对象
server = SocketServer.ThreadingTCPServer(ip_port,MyServer)
#调用对象的serve_forever方法
server.serve_forever()
client.py
import socket
sk = socket.socket()
ip_port = ('127.0.0.1',8009)
sk.connect(ip_port)
#设置阻塞模式下socket的超时时间为5s,socket的后续操作若在给定超时时间内没完成,将触发timeout异常
sk.settimeout(5)
while True:
get_data = sk.recv(1024)
print "get data %s" %get_data
inp = raw_input("plz input:").strip()
sk.sendall(inp)
if inp == "exit":
break
sk.close()
观察效果方法:
1.运行server.py,让server处于监听状态
2.运行多个client.py,使得多个客户端去连接服务器,即让服务器处理多个客户端的请求
五、基于socket、threading、select模块实现并发、多线程处理多个连接请求
select--用于异步阻塞,实现非阻塞I/O
threading---用于多线程处理请求
import socket
import threading
import select
def process(request,client_address):
print request,client_addr
conn = request
conn.sendall("welcome to phone 10086")
flag = True
while flag:
data = conn.recv(1024)
if data == "exit":
flag = False
elif data == "0":
conn.sendall("connect to man service")
else:
conn.sendall("plz input again")
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port = ('127.0.0.1',8002)
sk.bind(ip_port)
sk.listen(5)
while True:
#select模块以列表的形式接收4个参数:
#1.需要监控的可读文件(套接字)对象,list类型
#2.可写文件文件对象,list类型
#3.产生异常的文件对象,list类型
#4.超时设置
返回3个对象:
#1.读事件,list类型
#2、写事件,list类型
#3、异常对象,list类型
rs, ws,es =select.select([sk,],[],[],1)
print "looping"
#判断sk是否是本机上用于监听的socket
if sk in rs:
print 'get request'
request和client_addr分别是接收到的socket对象和地址+端口
request,client_addr = sk.accept()
#创建线程对象,接收处理线程处理函数,参数是端口+ip
t = threading.Thread(target=process,args=(request,client_addr))
t.daemon = False
#开始线程活动
t.start()
sk.close()