本章内容
- Socket介绍
- Socket参数介绍
- 基本Socket实例
- Socket实现多连接处理
- 通过Socket实现简单SSH
- 通过Socket实现文件传送
一、Socket介绍
socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”想网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
file模块是针对某个指定文件进行【打开】【读写】【关闭】
socket模块是针对 服务器 和 客户端 Socket进行【打开】【读写】【关闭】
看图:
一个简单的socket server和socket client 例子:
1 import socket 2
3 ip_port = ('127.0.0.1',9999) 4
5 #创建socket对象
6 sk = socket.socket() 7
8 #绑定允许链接的地址和端口
9 sk.bind(ip_port) 10
11 #监听端口,限制客户端连接数,超过5个,第6个直接断开
12 sk.listen(5) 13
14 #循环接受信息
15 while True: 16
17 #打印服务正在等待
18 print('server waiting.....') 19
20 #阻塞,等待接受客户端的请求,conn=创建的连接,addr=客户端IP和端口
21 conn,addr = sk.accept() 22
23 #一次接收1024字节
24 client_data = conn.recv(1024) 25
26 #接收的是字节,需要转成str类型
27 client_data_str = str(client_data,encoding="utf-8") 28
29 #打印接收的结果
30 print(client_data_str) 31
32 #发送信息给客户端
33 conn.sendall("不需要回复!") 34
35 #关闭连接
36 sk.close()
1 import socket 2
3 ip_port = ('127.0.0.1',9999) 4
5 #创建socket对象
6 sk = socket.socket 7
8 #制定服务器端的IP和端口
9 sk.connect(ip_port) 10
11 #向服务端发送信息
12 sk.sendall("我是客户端,我来了!") 13
14 # 接收服务端信息
15 server_reply = sk.recv(1024) 16
17 #将接收的信息转为字符串类型
18 server_reply_str = str(server_reply) 19
20 # 打印结果
21 print(server_reply) 22
23 # 关闭客户端
24 sk.close()
实现一个socket至少要分以下几步(伪代码):
Socket.socket = getSocket(type = "TCP") #设定好协议类型
connect(socket,address = "1.2.3.4", port = "80") #连接远程机器
send(socket,"Hellow world") #发送消息
close(socket) #关闭连接
地址簇:
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6
socket AF_UNIX 只能够用于单一的Unix系统进程间通信
类型:
socket.SOCK_STREAM 流式socket,for TCP(默认)
socket.SOCK_DGRAM 数据报式socket,for UDP
socke.SOCK_RAW原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据包但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET可靠的连续数据包服务
协议:
0 (默认)与特定的地址家族相关的协议,如果是0,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
二、参数介绍
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
socket.
socketpair
([family[, type[, proto]]])
socket.
create_connection
(address[, timeout[, source_address]])
socket.
getaddrinfo
(host, port, family=0, type=0, proto=0, flags=0) #获取要连接的对端主机地址
sk.bind(address)
将套接字绑定到地址。address地址的格式取决于地址簇。在AF_INET下,一元组(host,port)的形式表示地址
sk.listen(backlog)
开始监听传入链接。backlog指定在拒绝链接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的链接个数最大为5,这个值不能无限大,因为要在内核中维护连接队列。
sk.setblocking(bool)
是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。
sk.accept()
接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
接受TCP客户的连接(阻塞式)等待连接的到来
sk.connect(address)
连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
sk.connect_ex(address)
链接到address处的套接字。一般,address的格式为元组(hostname,port),如果链接出错,返回socket.error错误。
sk.connect_ex(address)
同上,只不过会有返回值,连接成功时返回0,连接失败时候返回编码,例如:10061
sk.close()
关闭套接字
sk.recv(bufsize[,flag])
接收套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。
sk.recvfrom(bufsize[,flag])
与recv()类似,但返回值是(data,address)。其中包含可以接收数据的字符串,address是发送数据的套接字地址。
sk.send(string[,flag])
将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小鱼string的字节大小。即:可能未将指定内容全部发送。
sk.sendall(string[,flag])
将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。
sk.sendto(string[,flag],address)
将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。
sk.settimeout(timeout)
设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为他们可能用于连接的操作(如client连接最多等待5s)
sk.getpeername()
返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)
sk.getsockname()
返回套接字自己的地址。通常是一个元组(ipaddr,port)
sk.fileno()
套接字的文件描述符
socket.sendfile(file,offset=0,count=None)
发送文件,但目前多数情况下并没有什么卵用
以上说了这么多,简单的讲那就是一脸懵逼,socket可以用来写一些网络协议,还比如文件的上传下载也是通过socket来实现的,还有发送邮件啊之类的,说白了就是两边进行相互通信。以上的用法一定要学会。
三、基本Socket实例
服务端:
1 import socket 2
3 server = socket.socket() #获得socket实例
4
5 server.bind(("localhost",9998)) #绑定ip port
6 server.listen() #开始监听
7 print("等待客户端的连接...") 8 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
9 print("新连接:",addr ) 10
11 data = conn.recv(1024) 12 print("收到消息:",data) 13
14 server.close()
客户端:
1 import socket 2
3 client = socket.socket() 4
5 client.connect(("localhost",9998)) 6
7 client.send(b"hey") 8
9 client.close()
以上就实现了一个可以接收信息的功能,但是呢,服务端接收一次后就退出了,在现实生过中我们希望服务端能够进行多次往返的通信对把?
想多了什么??while True,可以一直到死都要循环。看代码:
服务端:
1 import socket 2
3 server = socket.socket() #获得socket实例
4
5 server.bind(("localhost",9998)) #绑定ip port
6 server.listen() #开始监听
7 print("等待客户端的连接...") 8 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
9 print("新连接:",addr ) 10 while True: 11
12 data = conn.recv(1024) 13
14 print("收到消息:",data) 15 conn.send(data.upper()) 16
17 server.close()
客户端:
1 import socket 2
3 client = socket.socket() 4
5 client.connect(("localhost",9998)) 6
7 while True: 8 msg = input(">>:").strip() 9 if len(msg) == 0:continue
10 client.send( msg.encode("utf-8") ) 11
12 data = client.recv(1024) 13 print("来自服务器:",data) 14
15 client.close()
利用while True我们就实现了这个小小的功能,但是以上代码中,客户端已断开,服务器就会进入死循环,因为客户端已断开,服务器端就收不到数据了,但是不会报错,于是就进入死循环了
这里我们就可以加一个判断客户端是否断开代码:
1 import socket 2
3 server = socket.socket() #获得socket实例
4
5 server.bind(("localhost",9998)) #绑定ip port
6 server.listen() #开始监听
7 print("等待客户端的连接...") 8 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,直到有客户端连接进来...
9 print("新连接:",addr ) 10 while True: 11
12 data = conn.recv(1024) 13 if not data: 14 print("客户端断开了...") 15 break
16 print("收到消息:",data) 17 conn.send(data.upper()) 18
19 server.close()
四、Socket实现多连接处理
上面的代码虽然实现了服务端的多次交互,但是我们会发现,如果客户端断开了,服务器也会跟着立刻断开,因为服务器只有一个while循环,客户端一断开,服务端收不到数据,就会直接break跳出循环,然后程序就退出了,这显然不是我们想要的结果,我们想要的是,客户端如果断开了,我们这个服务端还可以为下一个客户端服务,它不能断,她接完一个客,擦完嘴角的遗留物,就要接下来勇敢的去接待一个客人。在这里如何实现呢?
1 conn,addr = server.accept() #接收并建立与客户端的连接,程序在此处开始阻塞,直到客户端连接进来.....
我们知道上面这句话负责等待并接收连接,对于上面那个程序,其实在while break之后,只要让程序再次回到上面这句代码这,就可以让服务端继续接下一个客户了。
1 import socket 2
3 server = socket.socket() #获得socket实例
4
5 server.bind(("localhost",9998)) #绑定ip port
6 server.listen() #开始监听
7
8 while True: #第一层loop
9 print("等待客户端的连接...") 10 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11 print("新连接:",addr ) 12 while True: 13
14 data = conn.recv(1024) 15 if not data: 16 print("客户端断开了...") 17 break #这里断开就会再次回到第一次外层的loop
18 print("收到消息:",data) 19 conn.send(data.upper()) 20
21 server.close()
以上我们就实现了可以让客户一个接一个的来,但是并不能实现多个客户一起上,就像一个马桶一次只能上一个人,但是我们知道就像qq,一个用户可以同时接收多个用户发送过来的消息,那该怎么办呢?那我们就要把马桶进行升级了,然后通过研究,哈哈就研究出了可以同时多个人上的马桶,那是什么呢?哈哈,我也不知道,不过我猜那应该就是粪坑了。。。哈哈哈。。。
五、通过Socket实现简单SSH
仅仅只发送消息、接收消息太没意思了。我们可以做一个极简版的ssh,就是客户端连接上服务器后,让服务器执行命令,并返回结果给客户端。
服务器端:
1 import socket 2 import os 3
4 server = socket.socket() #获得socket实例
5 #server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
6
7 server.bind(("localhost",9998)) #绑定ip port
8 server.listen() #开始监听
9
10 while True: #第一层loop
11 print("等待客户端的连接...") 12 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
13 print("新连接:",addr ) 14 while True: 15
16 data = conn.recv(1024) 17 if not data: 18 print("客户端断开了...") 19 break #这里断开就会再次回到第一次外层的loop
20 print("收到命令:",data) 21 res = os.popen(data.decode()).read() #py3 里socket发送的只有bytes,os.popen又只能接受str,所以要decode一下
22 print(len(res)) 23 conn.send(res.encode("utf-8")) 24
25 server.close()
1 import socket 2
3 client = socket.socket() 4
5 client.connect(("localhost",9998)) 6
7 while True: 8 msg = input(">>:").strip() 9 if len(msg) == 0:continue
10 client.send( msg.encode("utf-8") ) 11
12 data = client.recv(1024) 13 print(data.decode()) #命令执行结果
14
15 client.close()
上面代码我们虽然实现了一个简单的ssh,但是以上有3个问题:
1.不能执行top等类似的会持续输出的命令,这是因为,服务器端在收到客户端指令后,会一次性通过os.popen执行,并得到结果后返回给客户,但top这样的命令用os.popen执行你会发现永远都不会结束,所以客户端也永远拿不到返回。(真正的ssh是通过select异步等模块实现的。)
2.不能执行像cd这种没有返回的指令,因为客户端每发送一条指令,就会通过client.recv(1024)等待接收服务器端的返回结果,但是cd命令没有结果,服务器端调用conn.send(data)时是不会发送数据给客户端的。所以客户端就会一直等着,等到卡死了,也没有等到。在服务器端判断命令的执行返回结果的长度,如果结果为空,就自己加个结果返回给客户端,如写上“smd exec success,has no output.”
3.如果执行的命令返回结果的数据量比较大,会发现,结果返回不全,因为我们的客户写client.recv(1024),即客户端一次最多只接收1024个字节,如果服务器端返回的数据是2000字节,那有至少9百多字节是客户端第一次接收不了的,所以它就会暂时存在服务器的io发送缓冲区里,等客户端下次再接收数据的时候再发送过去。在这里,我们是可以适当的改client.recv(1024),但是socket每次接收和发送都是有最大数据限制的,毕竟网络宽带也是有限的,不能一次发太多,发送的数据最大量的限制就是缓冲区能缓存的数据的最大量,这个缓冲区的最大值在不同的系统上是不一样的,linux上最大一次可接收10mb左右的数据,官方的建议是不超过8k,并且数据要可以被2整除。
在上述过程中,我们要注意一个粘包的问题,什么是“粘包”?粘包就是服务器端你调用时send2次,但是你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里面,等到缓冲区满了、或者数据等待超时了,数据才会被send到客户端。这样就相当于把好几次的小数据平成一个大数据,统一发送到客户端了,这么做的目的是为了提高io利用效率,一次性发送总比连发好几次效率高嘛。但是这样就有一个问题,我们会发现2次的数据粘在一起发送过去了,而我们必须把粘包分开,因为不分开,就没有办法取出来服务器端返回的命令执行结果的大小。而且如果不分开数据就乱套了不是么。如果要解决粘包的问题的话,只有一个,就是让缓冲区超时,超时了,系统就不会等待缓冲区满,而会直接把数据发走,因为不能一直等后面的数据,等久了会造成数据延迟。
比如我们可以让他睡0.5秒,只要你今天这样做,明天老板就会让你滚蛋,炒股你去给我等0.5秒试试?其实我们可以服务器端每发送一个数据给客户端,就立刻等待客户端进行回应,即调用conn.recv(1024),由于recv在接收不到数据时是阻塞的,这样就会造成服务器端接收不到客户端的响应,就不会执行后面的conn.sendall(命令结果)的指令,收到客户端响应后,再发送命令结果时,缓冲区就已经被清空了,因为上一次数据已经被强制发到客户端了。代码如下:
1 #_*_coding:utf-8_*_
2 __author__ = 'Alex Li'
3
4
5 import socket 6 import os,subprocess 7
8
9 server = socket.socket() #获得socket实例
10 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11
12 server.bind(("localhost",9999)) #绑定ip port
13 server.listen() #开始监听
14
15 while True: #第一层loop
16 print("等待客户端的连接...") 17 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
18 print("新连接:",addr ) 19 while True: 20
21 data = conn.recv(1024) 22 if not data: 23 print("客户端断开了...") 24 break #这里断开就会再次回到第一次外层的loop
25 print("收到命令:",data) 26 #res = os.popen(data.decode()).read() #py3 里socket发送的只有bytes,os.popen又只能接受str,所以要decode一下
27 res = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE).stdout.read() #跟上面那条命令的效果是一样的
28 if len(res) == 0: 29 res = "cmd exec success,has not output!".encode("utf-8") 30 conn.send(str(len(res)).encode("utf-8")) #发送数据之前,先告诉客户端要发多少数据给它
31 print("等待客户ack应答...") 32 client_final_ack = conn.recv(1024) #等待客户端响应
33 print("客户应答:",client_final_ack.decode()) 34 print(type(res)) 35 conn.sendall(res) #发送端也有最大数据量限制,所以这里用sendall,相当于重复循环调用conn.send,直至数据发送完毕
36
37 server.close()
1 #_*_coding:utf-8_*_
2 __author__ = 'Alex Li'
3
4 import socket 5 import sys 6
7 client = socket.socket() 8
9 client.connect(("localhost",9999)) 10
11 while True: 12 msg = input(">>:").strip() 13 if len(msg) == 0:continue
14 client.send( msg.encode("utf-8") ) 15
16 res_return_size = client.recv(1024) #接收这条命令执行结果的大小
17 print("getting cmd result , ", res_return_size) 18 total_rece_size = int(res_return_size) 19 print("total size:",res_return_size) 20 client.send("准备好接收了,发吧loser".encode("utf-8")) 21 received_size = 0 #已接收到的数据
22 cmd_res = b''
23 f = open("test_copy.html","wb")#把接收到的结果存下来,一会看看收到的数据 对不对
24 while received_size != total_rece_size: #代表还没收完
25 data = client.recv(1024) 26 received_size += len(data) #为什么不是直接1024,还判断len干嘛,注意,实际收到的data有可能比1024少
27 cmd_res += data 28 else: 29 print("数据收完了",received_size) 30 #print(cmd_res.decode())
31 f.write(cmd_res) #把接收到的结果存下来,一会看看收到的数据 对不对
32 #print(data.decode()) #命令执行结果
33
34 client.close()
六、通过Socket实现文件传送
利用socketserver模块来实现:
· SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。
socketserver共有一下几种类型:
1 class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True) 2
3
4 class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True) 5
6
7 class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True) 8
9
10 class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
创建一个socketserver至少分一下几步:
首先,你必须创建一个请求处理程序类通过实例化这个类以及调用handle()方法,该方法将处理传入的请求。
其次,你必须实例化一个服务器的类,通过服务器的地址和请求处理程序类。
然后调用handle_request()或者serve_forever()方法来处理一个或多个请求。
最后,调用server_close()关闭套接字。
基本的socketserver代码:
1 import socketserver 2
3 class MyTCPHandler(socketserver.BaseRequestHandler): 4 """
5 The request handler class for our server. 6
7 It is instantiated once per connection to the server, and must 8 override the handle() method to implement communication to the 9 client. 10 """
11
12 def handle(self): 13 # self.request is the TCP socket connected to the client
14 self.data = self.request.recv(1024).strip() 15 print("{} wrote:".format(self.client_address[0])) 16 print(self.data) 17 # just send back the same data, but upper-cased
18 self.request.sendall(self.data.upper()) 19
20 if __name__ == "__main__": 21 HOST, PORT = "localhost", 9999
22
23 # Create the server, binding to localhost on port 9999
24 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 25
26 # Activate the server; this will keep running until you
27 # interrupt the program with Ctrl-C
28 server.serve_forever()
要实现socketserver并发,必须使用一下一个多并发的类:
class socketserver.
ForkingTCPServer
class socketserver.
ForkingUDPServer
class socketserver.
ThreadingTCPServer
class socketserver.
ThreadingUDPServer
server
=
socketserver.TCPServer((HOST, PORT), MyTCPHandler)
换成下面这个,就可以多并发了,这样,客户端每连进一个来,服务器端就会分配一个新的线程来处理这个客户端的请求
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
class socketserver.BaseServer(server_address,RequestHandlerClass)主要有一下方法:
1 class socketserver.BaseServer(server_address, RequestHandlerClass) 2 This is the superclass of all Server objects in the module. It defines the interface, given below, but does not implement most of the methods, which is done in subclasses. The two parameters are stored in the respective server_address and RequestHandlerClass attributes. 3
4 fileno() 5 Return an integer file descriptor for the socket on which the server is listening. This function is most commonly passed to selectors, to allow monitoring multiple servers in the same process. 6
7 handle_request() 8 Process a single request. This function calls the following methods in order: get_request(), verify_request(), and process_request(). If the user-provided handle() method of the handler class raises an exception, the server’s handle_error() method will be called. If no request is received within timeout seconds, handle_timeout() will be called and handle_request() will return. 9
10 serve_forever(poll_interval=0.5) 11 Handle requests until an explicit shutdown() request. Poll for shutdown every poll_interval seconds. Ignores the timeout attribute. It also calls service_actions(), which may be used by a subclass or mixin to provide actions specific to a given service. For example, the ForkingMixIn class uses service_actions() to clean up zombie child processes. 12
13 Changed in version 3.3: Added service_actions call to the serve_forever method. 14
15 service_actions() 16 This is called in the serve_forever() loop. This method can be overridden by subclasses or mixin classes to perform actions specific to a given service, such as cleanup actions. 17
18 New in version 3.3. 19
20 shutdown() 21 Tell the serve_forever() loop to stop and wait until it does. 22
23 server_close() 24 Clean up the server. May be overridden. 25
26 address_family 27 The family of protocols to which the server’s socket belongs. Common examples are socket.AF_INET and socket.AF_UNIX. 28
29 RequestHandlerClass 30 The user-provided request handler class; an instance of this class is created for each request. 31
32 server_address 33 The address on which the server is listening. The format of addresses varies depending on the protocol family; see the documentation for the socket module for details. For Internet protocols, this is a tuple containing a string giving the address, and an integer port number: ('127.0.0.1', 80), for example. 34
35 socket 36 The socket object on which the server will listen for incoming requests. 37
38 The server classes support the following class variables: 39
40 allow_reuse_address 41 Whether the server will allow the reuse of an address. This defaults to False, and can be set in subclasses to change the policy. 42
43 request_queue_size 44 The size of the request queue. If it takes a long time to process a single request, any requests that arrive while the server is busy are placed into a queue, up to request_queue_size requests. Once the queue is full, further requests from clients will get a “Connection denied” error. The default value is usually 5, but this can be overridden by subclasses. 45
46 socket_type 47 The type of socket used by the server; socket.SOCK_STREAM and socket.SOCK_DGRAM are two common values. 48
49 timeout 50 Timeout duration, measured in seconds, or None if no timeout is desired. If handle_request() receives no incoming requests within the timeout period, the handle_timeout() method is called. 51
52 There are various server methods that can be overridden by subclasses of base server classes like TCPServer; these methods aren’t useful to external users of the server object. 53
54 finish_request() 55 Actually processes the request by instantiating RequestHandlerClass and calling its handle() method. 56
57 get_request() 58 Must accept a request from the socket, and return a 2-tuple containing the new socket object to be used to communicate with the client, and the client’s address. 59
60 handle_error(request, client_address) 61 This function is called if the handle() method of a RequestHandlerClass instance raises an exception. The default action is to print the traceback to standard output and continue handling further requests. 62
63 handle_timeout() 64 This function is called when the timeout attribute has been set to a value other than None and the timeout period has passed with no requests being received. The default action for forking servers is to collect the status of any child processes that have exited, while in threading servers this method does nothing. 65
66 process_request(request, client_address) 67 Calls finish_request() to create an instance of the RequestHandlerClass. If desired, this function can create a new process or thread to handle the request; the ForkingMixIn and ThreadingMixIn classes do this. 68
69 server_activate() 70 Called by the server’s constructor to activate the server. The default behavior for a TCP server just invokes listen() on the server’s socket. May be overridden. 71
72 server_bind() 73 Called by the server’s constructor to bind the socket to the desired address. May be overridden. 74
75 verify_request(request, client_address) 76 Must return a Boolean value; if the value is True, the request will be processed, and if it’s False, the request will be denied. This function can be overridden to implement access controls for a server. The default implementation always returns True.
对于socketserver的更多详细解释:三达不留点某某某
看代码:
SocketServer_server:
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 # Author:Lyon
4
5 import socketserver 6
7 class LyonServer(socketserver.BaseRequestHandler): 8
9 def handle(self): 10
11 conn = self.request 12
13 conn.sendall(bytes("你好,欢迎登入!",encoding="utf-8")) 14 while True: 15 print("正在等待Clinet输入内容....") 16 ret_bytes = conn.recv(1024) 17 ret_str = str(ret_bytes,encoding="utf-8") 18 print(ret_str) 19 if ret_str == 'q': 20 break
21 inp = input("Server请输入要发送的内容-->>:") 22 conn.sendall(bytes(inp,encoding="utf-8")) 23
24 if __name__ == "__main__": 25 server =socketserver.ThreadingTCPServer(('192.168.115.247', 8888),LyonServer) 26 server.serve_forever()
SocketServer_client:
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 # Author:Lyon
4
5 import socket 6
7 obj = socket.socket() 8 obj.connect(('192.168.115.247', 8888)) 9 ret_bytes = obj.recv(1024) 10 ret_str = str(ret_bytes, encoding="utf-8") 11 print(ret_str) 12
13 while True: 14 inp = input("Clinet请输入要发送的内容-->>:") 15 if inp == "q": 16 obj.sendall(bytes(inp, encoding="utf-8")) 17 break
18 else: 19 obj.sendall(bytes(inp, encoding="utf-8")) 20 print("正在等待Server输入内容....") 21 ret = str(obj.recv(1024), encoding="utf-8") 22 print(ret) 23
24 obj.close()
注:本文仅为学习笔记、摘要。
详细来源:http://www.cnblogs.com/alex3714/articles/5830365.html
http://www.cnblogs.com/wupeiqi/articles/5040823.html
http://www.cnblogs.com/alex3714/articles/5227251.html