Python高手之路【十三】socket互联网编制程序,pythonsocket

Python高手之路【十三】socket网络编程,pythonsocket

威尼斯网址开户网站 ,Python socket编程,pythonsocket编程

python socket网络编程,pythonsocket

socket套接字:为了使2个不同应用程序进行通信。

两种套接字类型:基于文件的和基于网络的

1.基于文件(AF_LOCAL或AF_UNIX):代表Unix

2.面向网络(AF_INET):代表因特网

面向连接的套接字(SOCK_STREAM):TCP

面向无连接的套接字(SOCK_DGRAM):UDP

Python中的网络编程socket()模块

 

TCP 网络程序

serice服务端

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from socket import *
from time import ctime

HOST = ''  ##为空表示bind()函数可以绑定在所有有效的地址上
PORT=21567
BUFSIZ = 1024  ##缓冲区大小  1K
ADDR = (HOST,PORT)

tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)  ##允许最多多少个链接 后来的会被拒绝掉

while True:
    print 'waiting for connection...'
    tcpCliSock,addr = tcpSerSock.accept()  ##阻塞式线程
    print '...connected from:',addr

    while True:
        data = tcpCliSock.recv(BUFSIZ)

##阻塞式线程

if not data: break tcpCliSock.send('(%s) %s' % (ctime(),data)) tcpCliSock.close() tcpSerSock.close()

client 客户端

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from socket import *
 5 HOST = 'localhost'  ##
 6 PORT=21517
 7 BUFSIZ = 1024  ##缓冲区大小  1K
 8 ADDR = (HOST,PORT)
 9 
10 tcpCliSock = socket(AF_INET,SOCK_STREAM)
11 tcpCliSock.connect(ADDR)
12 
13 while True:
14     data = raw_input('> ')
15     if not data:
16         break
17     tcpCliSock.send(data)
18     data = tcpCliSock.recv(BUFSIZ)
19     if not data:
20         break
21     print data
22 tcpCliSock.close()

UDP程序 

service 服务端

威尼斯网址开户网站 1

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from socket import *
 5 from time import ctime
 6 
 7 HOST=''
 8 PORT=21567
 9 BUFSIZ = 1024
10 ADDR = (HOST,PORT)
11 
12 udpSerSock = socket(AF_INET,SOCK_DGRAM)
13 udpSerSock.bind(ADDR)
14 
15 while True:
16     print 'waiting for message....'
17     data , addr = udpSerSock.recvfrom(BUFSIZ)
18     udpSerSock.sendto('[%s] %s' % (ctime(),data),addr)
19     print '...received from and returned to:',addr
20 udpSerSock.close()

View Code

client 客户端

威尼斯网址开户网站 2

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from socket import *
 5 
 6 HOST='localhost'
 7 PORT=21567
 8 BUFSIZ=1024
 9 ADDR = (HOST,PORT)
10 
11 udpCliSock= socket(AF_INET,SOCK_DGRAM)
12 
13 while True:
14     data = raw_input('> ')
15     if not data:
16         break
17     udpCliSock.sendto(data,ADDR)
18     data,ADDR = udpCliSock.recvfrom(BUFSIZ)
19     if not data:
20         break
21     print data
22 
23 udpCliSock.close()

View Code

SocketService 通讯程序

服务端

威尼斯网址开户网站 3

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from SocketServer import (TCPServer as TCP,StreamRequestHandler as SRH)
 5 from time import ctime
 6 
 7 HOST = ''
 8 PORT = 21569
 9 ADDR = (HOST,PORT)
10 
11 class MyRequestHandler(SRH):
12     def handle(self):
13         print '...connected from:',self.client_address
14         self.wfile.write('[%s] %s' % (ctime(),self.rfile.readline()))
15 
16 tcpServ = TCP(ADDR,MyRequestHandler)
17 print 'waiting for connection...'
18 tcpServ.serve_forever()

View Code

客户端

威尼斯网址开户网站 4

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from socket import *
 5 HOST = 'localhost'  ##
 6 # HOST = '192.168.0.51'
 7 PORT=21569
 8 BUFSIZ = 1024  ##缓冲区大小  1K
 9 ADDR = (HOST,PORT)
10 
11 while True:
12     tcpCliSock = socket(AF_INET, SOCK_STREAM)
13     tcpCliSock.connect(ADDR)
14     data = raw_input('> ')
15     if not data:
16         break
17     tcpCliSock.send('%s\r\n' % data)
18     data = tcpCliSock.recv(BUFSIZ)
19     if not data:
20         break
21     print data.strip()
22     tcpCliSock.close()

View Code

 

socket网络编程,pythonsocket
socket套接字:为了使2个不同应用程序进行通信。
两种套接字类型:基于文件的和基于网络的 1.基于文件(A…

python socket网络编程,pythonsocket

import socket
clim=socket.socket()
clim.connect(("localhost",6969))
while True:
    thing=input(">>>>")
    clim.send(thing.encode("utf-8"))
    date = clim.recv(1024)
    print("reac:",date)
clim.close()

import socket
server=socket.socket()
server.bind(("localhost",6968))
server.listen()
while True:
    conn,addr=server.accept()
    while True:
        data=conn.recv(1024)
        print(data)
        msg=input("跟对方说什么:")
        #server.send(msg.encode("utf-8"))#这样写法是错的
        conn.send(msg.encode("utf-8"))


# server虽然是服务器对应的socket套接字,但其实际上没有connect任何的端,因而使用server.recv就会出现错误,
# 因为服务器的套接字对象只是listen了指定端口,而连接上可以供使用的套接字是server.accept()以后返回的套接字
# ,这是连接到服务器指定端口的套接字,因而可以用以通信

python——网络编程篇之socket原理,pythonsocket

  Python是一个很强大的网络编程工具,我们这里从socket模块开始

 

            处理多个连接的方法:forking、threading、asynchronous I/O

               
forking(分叉):有一个父进程监听客户端连接,当有连接过来时就复制一个子进程去处理与客户端的事务,客户端请求结束后该子进程就退出了。forking比较耗资源,每个子进程都有自己的内存空间,windows不支持forking。
             
  threading(线程):线程存在于同一进城中,共享内存,但存在同步问题,注意加锁

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import threading
 4 import time
 5  
 6 def test(num):
 7     time.sleep(1)
 8     print 'this is %s' %num 9  
10 for i in range(10):
11     t = threading.Thread(target=test, args=(i,))
12     t.start()

 

                asynchronous I/O:异步I/O,机制是select模块的select函数

 

Python是一个很强大的网络编程工具,我们这里从socket模块开始
处理多个连接的方法:forking、…

什么是客户/服务器架构?

什么是客户/服务器架构?不同的人有不同的答案。这要看你问的是什么人,以及指的是软件系统还是硬件系统了。但是,有一点是共通的:服务器是一个软件或硬件,用于提供客户需要的“服务”。服务器存在的唯一目的就是等待客户的请求,给这些客户服务,然后再等待其它的请求。另一方面,客户连上一个(预先已知的)服务器,提出自己的请求,
发送必要的数据,然后就等待服务器的完成请求或说明失败原因的反馈。服务器不停地处理外来的请求,而客户一次只能提出一个服务的请求,等待结果。然后结束这个事务。客户之后也可以再提出其它的请求,只是,这个请求会被视为另一个不同的事务了。

威尼斯网址开户网站 5

上图就是Internet 上典型的客户/服务器概念。 展示了如今最常见的客户/服务器结构。一个用户或客户电脑通过
Internet 从服务器上取数据。 这的确是一个客户/服务器架构的系统,
但还有更多类似的系统满足客户/服务器架构。而且,客户/服务器架构也可以应用到电脑硬件上。

Python  socket编程 (转)

情况二:传输文件

import socket
clim=socket.socket()
clim.connect(("localhost",6969))
f=open("注册码.txt","wb")
while True:
    thing=input(">>>>")
    clim.send(thing.encode("utf-8"))
    date = clim.recv(1024)
    print("reac:",date)
    f.write(date)
    f.flush()
clim.close()

import socket
import os
server=socket.socket()
server.bind(("localhost",6969))
server.listen()
while True:
    conn,addr=server.accept()
    while True:
        data=conn.recv(1024)
        print(data)
        #os.popen(data)
        f=open("D:\BaiduNetdiskDownload\python\PyCharm2017.X专业版注册码.txt")
        #server.send(msg.encode("utf-8"))
        data=f.read()
        conn.send(data.encode("utf-8"))

客户/服务器网络编程

在完成服务之前,服务器必需要先完成一些设置动作。先要创建一个通讯端点,让服务器能“监听”请求。你可以把我们的服务器比做一个公司的接待员或回答公司总线电话的话务员,一旦电话和设备安装完成,话务员也到了之后,服务就可以开始了。

在网络世界里,基本上也是这样——一旦通讯端点创建好之后,我们在“监听”的服务器就可以进入它那等待和处理客户请求的无限循环中了。当然,
我们也不能忘记在信纸上,杂志里,广告中印上公司的电话号码。否则,就没有人会打电话进来了!同样地,服务器在准备好之后,也要通知潜在的客户,让它们知道服务器已经准备好处理服务了。否则,没有人会提请求的。比方说,你建立了一个全新的网站。这个网站非常的出色,非常的吸引人,非常的有用,是所有网站中最酷的一个。但如果你不把网站的网址或者说统一资源定位符(URL)广而告之的话,没有人会知道这个网站的存在的。这个网站也就永远不见天日了。对于公司
总部的新电话也是这样,你不把电话公之于众,那就没有人会打电话进来。

现在,你对服务器如何工作已经有了一个很好的认识。你已经完成了最难的那一部分。客户端的编程相对服务器端来说就简单得多了。
所有的客户只要创建一个通讯端点,
建立到服务器的连接。然后客户就可以提出请求,请求中,也可以包含必要的数据交互。一旦请求处理完成,客户收到了结果,通讯就结束了。

Socket

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

基本上,Socket
是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入
 时,你会打开一个套接字,然后连接到
 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如
gtalk 和 skype 也是类似。任何网络通讯都是通过 Socket 来完成的。

Python 官方关于 Socket
的函数请看 

socket和file的区别:

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

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

威尼斯网址开户网站 6

先来创建一个socket服务端吧

威尼斯网址开户网站 7

 1 #coding:utf8
 2 
 3 import socket
 4 
 5 sk = socket.socket()
 6 sk.bind(("127.0.0.1",8080))
 7 sk.listen(5)
 8 
 9 conn,address = sk.accept()
10 sk.sendall(bytes("Hello world",encoding="utf-8"))

server
威尼斯网址开户网站 8

1 import socket
2 
3 obj = socket.socket()
4 obj.connect(("127.0.0.1",8080))
5 
6 ret = str(obj.recv(1024),encoding="utf-8")
7 print(ret)

View Code

 

socket更多功能

威尼斯网址开户网站 9

  1 def bind(self, address): # real signature unknown; restored from __doc__
  2         """
  3         bind(address)
  4         
  5         Bind the socket to a local address.  For IP sockets, the address is a
  6         pair (host, port); the host must refer to the local host. For raw packet
  7         sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])
  8         """
  9 '''将套接字绑定到本地地址。是一个IP套接字的地址对(主机、端口),主机必须参考本地主机。'''
 10         pass
 11 
 12     def close(self): # real signature unknown; restored from __doc__
 13         """
 14         close()
 15         
 16         Close the socket.  It cannot be used after this call.
 17         """
 18         '''关闭socket'''
 19         pass
 20 
 21     def connect(self, address): # real signature unknown; restored from __doc__
 22         """
 23         connect(address)
 24         
 25         Connect the socket to a remote address.  For IP sockets, the address
 26         is a pair (host, port).
 27         """
 28         '''将套接字连接到远程地址。IP套接字的地址'''
 29         pass
 30 
 31     def connect_ex(self, address): # real signature unknown; restored from __doc__
 32         """
 33         connect_ex(address) -> errno
 34         
 35         This is like connect(address), but returns an error code (the errno value)
 36         instead of raising an exception when an error occurs.
 37         """
 38         pass
 39 
 40     def detach(self): # real signature unknown; restored from __doc__
 41         """
 42         detach()
 43         
 44         Close the socket object without closing the underlying file descriptor.
 45         The object cannot be used after this call, but the file descriptor
 46         can be reused for other purposes.  The file descriptor is returned.
 47         """
 48 '''关闭套接字对象没有关闭底层的文件描述符。'''
 49         pass
 50 
 51     def fileno(self): # real signature unknown; restored from __doc__
 52         """
 53         fileno() -> integer
 54         
 55         Return the integer file descriptor of the socket.
 56         """
 57         '''返回整数的套接字的文件描述符。'''
 58         return 0
 59 
 60     def getpeername(self): # real signature unknown; restored from __doc__
 61         """
 62         getpeername() -> address info
 63         
 64         Return the address of the remote endpoint.  For IP sockets, the address
 65         info is a pair (hostaddr, port).
 66             """
 67         '''返回远程端点的地址。IP套接字的地址'''
 68         pass
 69 
 70     def getsockname(self): # real signature unknown; restored from __doc__
 71         """
 72         getsockname() -> address info
 73         
 74         Return the address of the local endpoint.  For IP sockets, the address
 75         info is a pair (hostaddr, port).
 76         """
 77         '''返回远程端点的地址。IP套接字的地址'''
 78         pass
 79 
 80     def getsockopt(self, level, option, buffersize=None): # real signature unknown; restored from __doc__
 81         """
 82         getsockopt(level, option[, buffersize]) -> value
 83         
 84         Get a socket option.  See the Unix manual for level and option.
 85         If a nonzero buffersize argument is given, the return value is a
 86         string of that length; otherwise it is an integer.
 87         """
 88         '''得到一个套接字选项'''
 89         pass
 90 
 91     def gettimeout(self): # real signature unknown; restored from __doc__
 92         """
 93         gettimeout() -> timeout
 94         
 95         Returns the timeout in seconds (float) associated with socket 
 96         operations. A timeout of None indicates that timeouts on socket 
 97         operations are disabled.
 98         """
 99         '''返回的超时秒数(浮动)与套接字相关联'''
100         return timeout
101 
102     def ioctl(self, cmd, option): # real signature unknown; restored from __doc__
103         """
104         ioctl(cmd, option) -> long
105         
106         Control the socket with WSAIoctl syscall. Currently supported 'cmd' values are
107         SIO_RCVALL:  'option' must be one of the socket.RCVALL_* constants.
108         SIO_KEEPALIVE_VALS:  'option' is a tuple of (onoff, timeout, interval).
109         """
110         return 0
111 
112     def listen(self, backlog=None): # real signature unknown; restored from __doc__
113         """
114         listen([backlog])
115         
116         Enable a server to accept connections.  If backlog is specified, it must be
117         at least 0 (if it is lower, it is set to 0); it specifies the number of
118         unaccepted connections that the system will allow before refusing new
119         connections. If not specified, a default reasonable value is chosen.
120         """
121         '''使服务器能够接受连接。'''
122         pass
123 
124     def recv(self, buffersize, flags=None): # real signature unknown; restored from __doc__
125         """
126         recv(buffersize[, flags]) -> data
127         
128         Receive up to buffersize bytes from the socket.  For the optional flags
129         argument, see the Unix manual.  When no data is available, block until
130         at least one byte is available or until the remote end is closed.  When
131         the remote end is closed and all data is read, return the empty string.
132         """
133 '''当没有数据可用,阻塞,直到至少一个字节是可用的或远程结束之前关闭。'''
134         pass
135 
136     def recvfrom(self, buffersize, flags=None): # real signature unknown; restored from __doc__
137         """
138         recvfrom(buffersize[, flags]) -> (data, address info)
139         
140         Like recv(buffersize, flags) but also return the sender's address info.
141         """
142         pass
143 
144     def recvfrom_into(self, buffer, nbytes=None, flags=None): # real signature unknown; restored from __doc__
145         """
146         recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)
147         
148         Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.
149         """
150         pass
151 
152     def recv_into(self, buffer, nbytes=None, flags=None): # real signature unknown; restored from __doc__
153         """
154         recv_into(buffer, [nbytes[, flags]]) -> nbytes_read
155         
156         A version of recv() that stores its data into a buffer rather than creating 
157         a new string.  Receive up to buffersize bytes from the socket.  If buffersize 
158         is not specified (or 0), receive up to the size available in the given buffer.
159         
160         See recv() for documentation about the flags.
161         """
162         pass
163 
164     def send(self, data, flags=None): # real signature unknown; restored from __doc__
165         """
166         send(data[, flags]) -> count
167         
168         Send a data string to the socket.  For the optional flags
169         argument, see the Unix manual.  Return the number of bytes
170         sent; this may be less than len(data) if the network is busy.
171         """
172         '''发送一个数据字符串到套接字。'''
173         pass
174 
175     def sendall(self, data, flags=None): # real signature unknown; restored from __doc__
176         """
177         sendall(data[, flags])
178         
179         Send a data string to the socket.  For the optional flags
180         argument, see the Unix manual.  This calls send() repeatedly
181         until all data is sent.  If an error occurs, it's impossible
182         to tell how much data has been sent.
183         """
184         '''发送一个数据字符串到套接字,直到所有数据发送完成'''
185         pass
186 
187     def sendto(self, data, flags=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__ 
188         """
189         sendto(data[, flags], address) -> count
190         
191         Like send(data, flags) but allows specifying the destination address.
192         For IP sockets, the address is a pair (hostaddr, port).
193         """
194         pass
195 
196     def setblocking(self, flag): # real signature unknown; restored from __doc__
197         """
198         setblocking(flag)
199         
200         Set the socket to blocking (flag is true) or non-blocking (false).
201         setblocking(True) is equivalent to settimeout(None);
202         setblocking(False) is equivalent to settimeout(0.0).
203         """
204 '''是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。'''
205         pass
206 
207     def setsockopt(self, level, option, value): # real signature unknown; restored from __doc__
208         """
209         setsockopt(level, option, value)
210         
211         Set a socket option.  See the Unix manual for level and option.
212         The value argument can either be an integer or a string.
213         """
214         pass
215 
216     def settimeout(self, timeout): # real signature unknown; restored from __doc__
217         """
218         settimeout(timeout)
219         
220         Set a timeout on socket operations.  'timeout' can be a float,
221         giving in seconds, or None.  Setting a timeout of None disables
222         the timeout feature and is equivalent to setblocking(1).
223         Setting a timeout of zero is the same as setblocking(0).
224         """
225         pass
226 
227     def share(self, process_id): # real signature unknown; restored from __doc__
228         """
229         share(process_id) -> bytes
230         
231         Share the socket with another process.  The target process id
232         must be provided and the resulting bytes object passed to the target
233         process.  There the shared socket can be instantiated by calling
234         socket.fromshare().
235         """
236         return b""
237 
238     def shutdown(self, flag): # real signature unknown; restored from __doc__
239         """
240         shutdown(flag)
241         
242         Shut down the reading side of the socket (flag == SHUT_RD), the writing side
243         of the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR).
244         """
245         pass
246 
247     def _accept(self): # real signature unknown; restored from __doc__
248         """
249         _accept() -> (integer, address info)
250         
251         Wait for an incoming connection.  Return a new socket file descriptor
252         representing the connection, and the address of the client.
253         For IP sockets, the address info is a pair (hostaddr, port).
254         """
255         pass
256     

View Code

 

sk.bind(address)

  s.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)

  同上,只不过会有返回值,连接成功时返回 0
,连接失败时候返回编码,例如:10061

sk.close()

  关闭套接字

sk.recv(bufsize[,flag])

  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,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()

  套接字的文件描述符

 

TCP:

威尼斯网址开户网站 10

 1 import  socketserver
 2 服务端
 3 
 4 class Myserver(socketserver.BaseRequestHandler):
 5 
 6     def handle(self):
 7 
 8         conn = self.request
 9         conn.sendall(bytes("你好,我是机器人",encoding="utf-8"))
10         while True:
11             ret_bytes = conn.recv(1024)
12             ret_str = str(ret_bytes,encoding="utf-8")
13             if ret_str == "q":
14                 break
15             conn.sendall(bytes(ret_str+"你好我好大家好",encoding="utf-8"))
16 
17 if __name__ == "__main__":
18     server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Myserver)
19     server.serve_forever()
20 
21 客户端
22 
23 import socket
24 
25 obj = socket.socket()
26 
27 obj.connect(("127.0.0.1",8080))
28 
29 ret_bytes = obj.recv(1024)
30 ret_str = str(ret_bytes,encoding="utf-8")
31 print(ret_str)
32 
33 while True:
34     inp = input("你好请问您有什么问题? \n >>>")
35     if inp == "q":
36         obj.sendall(bytes(inp,encoding="utf-8"))
37         break
38     else:
39         obj.sendall(bytes(inp, encoding="utf-8"))
40         ret_bytes = obj.recv(1024)
41         ret_str = str(ret_bytes,encoding="utf-8")
42         print(ret_str)

机器人聊天
威尼斯网址开户网站 11

 1 服务端
 2 
 3 import socket
 4 
 5 sk = socket.socket()
 6 
 7 sk.bind(("127.0.0.1",8080))
 8 sk.listen(5)
 9 
10 while True:
11     conn,address = sk.accept()
12     conn.sendall(bytes("欢迎光临我爱我家",encoding="utf-8"))
13 
14     size = conn.recv(1024)
15     size_str = str(size,encoding="utf-8")
16     file_size = int(size_str)
17 
18     conn.sendall(bytes("开始传送", encoding="utf-8"))
19 
20     has_size = 0
21     f = open("db_new.jpg","wb")
22     while True:
23         if file_size == has_size:
24             break
25         date = conn.recv(1024)
26         f.write(date)
27         has_size += len(date)
28 
29     f.close()
30 
31 客户端
32 
33 import socket
34 import os
35 
36 obj = socket.socket()
37 
38 obj.connect(("127.0.0.1",8080))
39 
40 ret_bytes = obj.recv(1024)
41 ret_str = str(ret_bytes,encoding="utf-8")
42 print(ret_str)
43 
44 size = os.stat("yan.jpg").st_size
45 obj.sendall(bytes(str(size),encoding="utf-8"))
46 
47 obj.recv(1024)
48 
49 with open("yan.jpg","rb") as f:
50     for line in f:
51         obj.sendall(line)

上传文件

 

UDP:

威尼斯网址开户网站 12

 1 import socket
 2 ip_port = ('127.0.0.1',9999)
 3 sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
 4 sk.bind(ip_port)
 5 
 6 while True:
 7     data = sk.recv(1024)
 8     print data
 9 
10 
11 
12 
13 import socket
14 ip_port = ('127.0.0.1',9999)
15 
16 sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
17 while True:
18     inp = input('数据:').strip()
19     if inp == 'exit':
20         break
21     sk.sendto(bytes(inp,encoding = "utf-8"),ip_port)
22 
23 sk.close()
24 
25 udp传输

UDP传输

 

WEB服务应用:

威尼斯网址开户网站 13

 1 #coding:utf-8
 2 import socket
 3   
 4 def handle_request(client):
 5     buf = client.recv(1024)
 6     client.send("HTTP/1.1 200 OK\r\n\r\n")
 7     client.send("Hello, World")
 8   
 9 def main():
10     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
11     sock.bind(('localhost',8080))
12     sock.listen(5)
13   
14     while True:
15         connection, address = sock.accept()
16         handle_request(connection)
17         connection.close()
18   
19 if __name__ == '__main__':
20   main()

UDP传输

 

socket编程,pythonsocket编程 Python
socket编程 (转) Socket
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打…

情况三:实现对服务器端的系统操作

import socket
client=socket.socket()
client.connect(("localhost",6969))
while True:
    thing=input(">>>>")
    client.send(thing.encode("utf-8"))
    date = client.recv(1024)
    print("reac:",date)
clim.close()

import socket
import os
server=socket.socket()
server.bind(("localhost",6969))
server.listen()
while True:
    conn,addr=server.accept()
    while True:
        data=conn.recv(1024)
        print(data)
        res=os.popen(data)
        # os.popen(command[, mode[, bufsize]])执行系统命令,执行结果写到一个临时文件里面,返回值是这个打开的文件对象。mode默认值为r,即默认以只读方式打开文件;
        # buffersize默认是系统缓冲区大小(buffer缓冲,此概念适用于磁盘写数据;cache缓存,此概念适用于磁盘读数据)。
        #
        # 既然返回的是一个文件对象,那么接下来可以理解os.popen().read(),是把这个文件对象中的内容读出来,
        # 返回值就是文件中的内容。
        conn.send(res)

 

socket网络编程,pythonsocket import
socketclim = socket.socket()clim.connect(( ” localhost ” ,6969 )) while
True: thing =input( ” ” ) clim.send(thing.encode( ” utf-8 “…

什么是套接字? 

套接字是一种具有之前所说的“通讯端点”概念的计算机网络数据结构。网络化的应用程序在开始任何通讯之前都必需要创建套接字。就像电话的插口一样,没有它就完全没办法通讯。套接字起源于
20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD
Unix。因此,有时人们也把套接字称为“伯克利套接字”或“BSD
套接字”。一开始,套接字被设计用在同一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或
IPC。套接字有两种,分别是基于文件型的和基于网络型的。

Unix 套接字是我们要介绍的第一个套接字家族。其“家族名”为 AF_UNIX(在
POSIX1.g 标准中也叫 AF_LOCAL),表示“地址家族:UNIX”。包括 Python
在内的大多数流行平台上都使用术语“地址家族”及其缩写“AF”。而老一点的系统中,地址家族被称为“域”或“协议家族”,并使用缩写“PF”而不是“AF”。同样的,AF_LOCAL(在
2000-2001 年被列为标准)将会代替
AF_UNIX。不过,为了向后兼容,很多系统上,两者是等价的。Python
自己则仍然使用
AF_UNIX。由于两个进程都运行在同一台机器上,而且这些套接字是基于文件的。所以,它们的底层结构是由文件系统来支持的。这样做相当有道理,因为,同一台电脑上,文件系统的确是不同的进程都能访问的。

另一种套接字是基于网络的,它有自己的家族名字: AF_INET,或叫“地址家族:
Internet”。 还有一种地址家族 AF_INET6
被用于网际协议第 6 版(IPv6)寻址上。还有一些其它的地址家族,不过,它们要么是只用在某个平台上,要么就是已经被废弃,或是很少被使用,或是根本就还没有实现。所有地址家族中,AF_INET
是使用最广泛的一个。Python 2.5 中加入了一种 Linux
套接字的支持:AF_NETLINK(无连接[见下])套接字家族让用户代码与内核代码之间的
IPC 可以使用标准 BSD
套接字接口。而且,相对之前那些往操作系统中加入新的系统调用,proc
文件系统支持或是“IOCTL”等笨重的方案来说,这种方法显得更为优美,更为安全。

Python 只支持 AF_UNIX,AF_NETLINK,和 AF_INET
家族。由于我们只关心网络编程,所以在本章的大部分时候,我们都只用
AF_INET

套接字地址:主机与端口

如果把套接字比做电话的插口——即通讯的最底层结构,那主机与端口就像区号与电话号码的一对组合。有了能打电话的硬件还不够,你还要知道你要打给谁,往哪打。一个
Internet
地址由网络通讯所必需的主机与端口组成。而且不用说,另一端一定要有人在听才可以。否则,你就会听到熟悉的声音“对不起,您拨的是空号,请查对后再播”。你在上网的时候,可能也见过类似的情况,如“不能连接该服务器。服务器无响应或不可达”。

合法的端口号范围为 0 到 65535。其中,小于 1024
的端口号为系统保留端口。如果你所使用的是 Unix
操作系统,保留的端口号(及其对应的服务/协议和套接字类型)可以通过/etc/services文件获得。常用端口号列表可以从下面这个网站获得:

socket()模块函数

 我们先用一个实例来说明socket函数的基本使用,在本实例中会创建一个 TCP
服务器程序,这个程序会把客户发送过来的字符串加上一个时间戳(格式:'[时间]数据’)返回给客户。

TCP 时间戳服务器 (t_server.py):

 

import socket
import time

host = '127.0.0.1'
port = 21567
bufsiz = 1024
add = (host,port)

tcpSerSock = socket.socket()
tcpSerSock.bind(add)
tcpSerSock.listen(5)

while True:
    print('waiting for connection ... ')
    tcpCliSock,address = tcpSerSock.accept()
    print('...connected from : ',address)
    while True:
        recv_data = tcpCliSock.recv(bufsiz)
        recv_data = str(recv_data,encoding='utf-8')
        if not recv_data:
            break
        tcpCliSock.sendall(bytes('[%s] %s' % (time.ctime(),recv_data),encoding='utf-8'))

 

sk.bind(address)

  s.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)

  同上,只不过会有返回值,连接成功时返回 0
,连接失败时候返回编码,例如:10061

sk.close()

  关闭套接字

sk.recv(bufsize[,flag])

  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,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()

  套接字的文件描述符

 

TCP 时间戳客户端(t_client.py) :

import socket

host = '127.0.0.1'
port = 21567
bufsiz = 1024
addr = (host,port)

tcpCliSock = socket.socket()
tcpCliSock.connect(addr)

while True:
    data = input('> ')
    if not data:
        break
    tcpCliSock.sendall(bytes(data,encoding='utf-8'))
    data = tcpCliSock.recv(bufsiz)
    recv_data = str(data,encoding='utf-8')
    if not recv_data:
        break
    print(recv_data)

tcpCliSock.close()

运行我们的客户端与服务器程序 :

先运行服务端t_server.py文件

威尼斯网址开户网站 14

下面就是客户端的输入与输出,不输入数据,直接按回车键就可以退出程序:

威尼斯网址开户网站 15

上面的实例中,无论发送还是接收,都是以字符串的形式,下面一个实例是发送图片文件及接收图片文件:

威尼斯网址开户网站 16

 1 import socket
 2 
 3 sk = socket.socket()
 4 sk.bind(('127.0.0.1',9999,))
 5 sk.listen(5)
 6 
 7 while True:
 8     conn,address = sk.accept()
 9     conn.sendall(bytes('welcome to conair',encoding='utf-8'))
10 
11     #先接收文件大小,然后再开始接收
12     file_size = str(conn.recv(1024),encoding='utf-8')
13 
14     #为解决粘包,设置的一个标志
15     conn.sendall(bytes('ko',encoding = 'utf-8'))
16 
17     total_size = int(file_size)
18     has_recv = 0
19 
20     f = open('new.jpg','wb')
21 
22     while True:
23         if total_size == has_recv:
24             break
25         data = conn.recv(1024)
26         f.write(data)
27         has_recv += len(data)
28     f.close()

服务器端文件
威尼斯网址开户网站 17

 1 import socket
 2 import os
 3 
 4 obj = socket.socket()
 5 obj.connect(('127.0.0.1',9999))
 6 
 7 ret_bytes = obj.recv(1024)
 8 ret_str = str(ret_bytes,encoding='utf-8')
 9 print(ret_str)
10 
11 #获取图片文件大小,然后发送
12 size = os.stat('06.jpg').st_size
13 obj.sendall(bytes(str(size),encoding='utf-8'))
14 
15 obj.recv(1024)
16 
17 with open('06.jpg','rb') as f :
18     for line in f:
19         obj.sendall(line)
20 
21 obj.close()

客户端文件

socketserver模块实现并发操作

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程”
,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程”
专门负责处理当前客户端的所有请求。

威尼斯网址开户网站 18

ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个
线程”,该线程用来和客户端进行交互。

1、ThreadingTCPServer基础

使用ThreadingTCPServer:

  • 创建一个继承自 SocketServer.BaseRequestHandler 的类
  • 类中必须定义一个名称为 handle 的方法
  • 启动ThreadingTCPServer

威尼斯网址开户网站 19

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import SocketServer
 4 
 5 class MyServer(SocketServer.BaseRequestHandler):
 6 
 7     def handle(self):
 8         # print self.request,self.client_address,self.server
 9         conn = self.request
10         conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
11         Flag = True
12         while Flag:
13             data = conn.recv(1024)
14             if data == 'exit':
15                 Flag = False
16             elif data == '0':
17                 conn.sendall('通过可能会被录音.balabala一大推')
18             else:
19                 conn.sendall('请重新输入.')
20 
21 
22 if __name__ == '__main__':
23     server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
24     server.serve_forever()
25 
26 SocketServer实现服务器

socketserver服务端
威尼斯网址开户网站 20

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 
 6 
 7 ip_port = ('127.0.0.1',8009)
 8 sk = socket.socket()
 9 sk.connect(ip_port)
10 sk.settimeout(5)
11 
12 while True:
13     data = sk.recv(1024)
14     print 'receive:',data
15     inp = raw_input('please input:')
16     sk.sendall(inp)
17     if inp == 'exit':
18         break
19 
20 sk.close()
21 
22 客户端

socketserver客户端

2、ThreadingTCPServer源码剖析

ThreadingTCPServer的类图关系如下:

威尼斯网址开户网站 21

内部调用流程为:

  • 启动服务端程序
  • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和
    端口
  • 执行 BaseServer.__init__
    方法,将自定义的继承自SocketServer.BaseRequestHandler 的类
    MyRequestHandle赋值给 self.RequestHandlerClass
  • 执行 BaseServer.server_forever 方法,While
    循环一直监听是否有客户端请求到达 …
  • 当客户端连接到达服务器
  • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程”
    用来处理请求
  • 执行 ThreadingMixIn.process_request_thread 方法
  • 执行 BaseServer.finish_request
    方法,执行 self.RequestHandlerClass()  即:执行 自定义
    MyRequestHandler
    的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用
    MyRequestHandler的handle方法)

ThreadingTCPServer相关源码:

威尼斯网址开户网站 22

  1 class BaseServer:
  2 
  3     """Base class for server classes.
  4 
  5     Methods for the caller:
  6 
  7     - __init__(server_address, RequestHandlerClass)
  8     - serve_forever(poll_interval=0.5)
  9     - shutdown()
 10     - handle_request()  # if you do not use serve_forever()
 11     - fileno() -> int   # for select()
 12 
 13     Methods that may be overridden:
 14 
 15     - server_bind()
 16     - server_activate()
 17     - get_request() -> request, client_address
 18     - handle_timeout()
 19     - verify_request(request, client_address)
 20     - server_close()
 21     - process_request(request, client_address)
 22     - shutdown_request(request)
 23     - close_request(request)
 24     - handle_error()
 25 
 26     Methods for derived classes:
 27 
 28     - finish_request(request, client_address)
 29 
 30     Class variables that may be overridden by derived classes or
 31     instances:
 32 
 33     - timeout
 34     - address_family
 35     - socket_type
 36     - allow_reuse_address
 37 
 38     Instance variables:
 39 
 40     - RequestHandlerClass
 41     - socket
 42 
 43     """
 44 
 45     timeout = None
 46 
 47     def __init__(self, server_address, RequestHandlerClass):
 48         """Constructor.  May be extended, do not override."""
 49         self.server_address = server_address
 50         self.RequestHandlerClass = RequestHandlerClass
 51         self.__is_shut_down = threading.Event()
 52         self.__shutdown_request = False
 53 
 54     def server_activate(self):
 55         """Called by constructor to activate the server.
 56 
 57         May be overridden.
 58 
 59         """
 60         pass
 61 
 62     def serve_forever(self, poll_interval=0.5):
 63         """Handle one request at a time until shutdown.
 64 
 65         Polls for shutdown every poll_interval seconds. Ignores
 66         self.timeout. If you need to do periodic tasks, do them in
 67         another thread.
 68         """
 69         self.__is_shut_down.clear()
 70         try:
 71             while not self.__shutdown_request:
 72                 # XXX: Consider using another file descriptor or
 73                 # connecting to the socket to wake this up instead of
 74                 # polling. Polling reduces our responsiveness to a
 75                 # shutdown request and wastes cpu at all other times.
 76                 r, w, e = _eintr_retry(select.select, [self], [], [],
 77                                        poll_interval)
 78                 if self in r:
 79                     self._handle_request_noblock()
 80         finally:
 81             self.__shutdown_request = False
 82             self.__is_shut_down.set()
 83 
 84     def shutdown(self):
 85         """Stops the serve_forever loop.
 86 
 87         Blocks until the loop has finished. This must be called while
 88         serve_forever() is running in another thread, or it will
 89         deadlock.
 90         """
 91         self.__shutdown_request = True
 92         self.__is_shut_down.wait()
 93 
 94     # The distinction between handling, getting, processing and
 95     # finishing a request is fairly arbitrary.  Remember:
 96     #
 97     # - handle_request() is the top-level call.  It calls
 98     #   select, get_request(), verify_request() and process_request()
 99     # - get_request() is different for stream or datagram sockets
100     # - process_request() is the place that may fork a new process
101     #   or create a new thread to finish the request
102     # - finish_request() instantiates the request handler class;
103     #   this constructor will handle the request all by itself
104 
105     def handle_request(self):
106         """Handle one request, possibly blocking.
107 
108         Respects self.timeout.
109         """
110         # Support people who used socket.settimeout() to escape
111         # handle_request before self.timeout was available.
112         timeout = self.socket.gettimeout()
113         if timeout is None:
114             timeout = self.timeout
115         elif self.timeout is not None:
116             timeout = min(timeout, self.timeout)
117         fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
118         if not fd_sets[0]:
119             self.handle_timeout()
120             return
121         self._handle_request_noblock()
122 
123     def _handle_request_noblock(self):
124         """Handle one request, without blocking.
125 
126         I assume that select.select has returned that the socket is
127         readable before this function was called, so there should be
128         no risk of blocking in get_request().
129         """
130         try:
131             request, client_address = self.get_request()
132         except socket.error:
133             return
134         if self.verify_request(request, client_address):
135             try:
136                 self.process_request(request, client_address)
137             except:
138                 self.handle_error(request, client_address)
139                 self.shutdown_request(request)
140 
141     def handle_timeout(self):
142         """Called if no new request arrives within self.timeout.
143 
144         Overridden by ForkingMixIn.
145         """
146         pass
147 
148     def verify_request(self, request, client_address):
149         """Verify the request.  May be overridden.
150 
151         Return True if we should proceed with this request.
152 
153         """
154         return True
155 
156     def process_request(self, request, client_address):
157         """Call finish_request.
158 
159         Overridden by ForkingMixIn and ThreadingMixIn.
160 
161         """
162         self.finish_request(request, client_address)
163         self.shutdown_request(request)
164 
165     def server_close(self):
166         """Called to clean-up the server.
167 
168         May be overridden.
169 
170         """
171         pass
172 
173     def finish_request(self, request, client_address):
174         """Finish one request by instantiating RequestHandlerClass."""
175         self.RequestHandlerClass(request, client_address, self)
176 
177     def shutdown_request(self, request):
178         """Called to shutdown and close an individual request."""
179         self.close_request(request)
180 
181     def close_request(self, request):
182         """Called to clean up an individual request."""
183         pass
184 
185     def handle_error(self, request, client_address):
186         """Handle an error gracefully.  May be overridden.
187 
188         The default is to print a traceback and continue.
189 
190         """
191         print '-'*40
192         print 'Exception happened during processing of request from',
193         print client_address
194         import traceback
195         traceback.print_exc() # XXX But this goes to stderr!
196         print '-'*40
197 
198 BaseServer

BaseServer
威尼斯网址开户网站 23

  1 class TCPServer(BaseServer):
  2 
  3     """Base class for various socket-based server classes.
  4 
  5     Defaults to synchronous IP stream (i.e., TCP).
  6 
  7     Methods for the caller:
  8 
  9     - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
 10     - serve_forever(poll_interval=0.5)
 11     - shutdown()
 12     - handle_request()  # if you don't use serve_forever()
 13     - fileno() -> int   # for select()
 14 
 15     Methods that may be overridden:
 16 
 17     - server_bind()
 18     - server_activate()
 19     - get_request() -> request, client_address
 20     - handle_timeout()
 21     - verify_request(request, client_address)
 22     - process_request(request, client_address)
 23     - shutdown_request(request)
 24     - close_request(request)
 25     - handle_error()
 26 
 27     Methods for derived classes:
 28 
 29     - finish_request(request, client_address)
 30 
 31     Class variables that may be overridden by derived classes or
 32     instances:
 33 
 34     - timeout
 35     - address_family
 36     - socket_type
 37     - request_queue_size (only for stream sockets)
 38     - allow_reuse_address
 39 
 40     Instance variables:
 41 
 42     - server_address
 43     - RequestHandlerClass
 44     - socket
 45 
 46     """
 47 
 48     address_family = socket.AF_INET
 49 
 50     socket_type = socket.SOCK_STREAM
 51 
 52     request_queue_size = 5
 53 
 54     allow_reuse_address = False
 55 
 56     def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
 57         """Constructor.  May be extended, do not override."""
 58         BaseServer.__init__(self, server_address, RequestHandlerClass)
 59         self.socket = socket.socket(self.address_family,
 60                                     self.socket_type)
 61         if bind_and_activate:
 62             try:
 63                 self.server_bind()
 64                 self.server_activate()
 65             except:
 66                 self.server_close()
 67                 raise
 68 
 69     def server_bind(self):
 70         """Called by constructor to bind the socket.
 71 
 72         May be overridden.
 73 
 74         """
 75         if self.allow_reuse_address:
 76             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 77         self.socket.bind(self.server_address)
 78         self.server_address = self.socket.getsockname()
 79 
 80     def server_activate(self):
 81         """Called by constructor to activate the server.
 82 
 83         May be overridden.
 84 
 85         """
 86         self.socket.listen(self.request_queue_size)
 87 
 88     def server_close(self):
 89         """Called to clean-up the server.
 90 
 91         May be overridden.
 92 
 93         """
 94         self.socket.close()
 95 
 96     def fileno(self):
 97         """Return socket file number.
 98 
 99         Interface required by select().
100 
101         """
102         return self.socket.fileno()
103 
104     def get_request(self):
105         """Get the request and client address from the socket.
106 
107         May be overridden.
108 
109         """
110         return self.socket.accept()
111 
112     def shutdown_request(self, request):
113         """Called to shutdown and close an individual request."""
114         try:
115             #explicitly shutdown.  socket.close() merely releases
116             #the socket and waits for GC to perform the actual close.
117             request.shutdown(socket.SHUT_WR)
118         except socket.error:
119             pass #some platforms may raise ENOTCONN here
120         self.close_request(request)
121 
122     def close_request(self, request):
123         """Called to clean up an individual request."""
124         request.close()
125 
126 TCPServer

TCPServer
威尼斯网址开户网站 24

 1 class ThreadingMixIn:
 2     """Mix-in class to handle each request in a new thread."""
 3 
 4     # Decides how threads will act upon termination of the
 5     # main process
 6     daemon_threads = False
 7 
 8     def process_request_thread(self, request, client_address):
 9         """Same as in BaseServer but as a thread.
10 
11         In addition, exception handling is done here.
12 
13         """
14         try:
15             self.finish_request(request, client_address)
16             self.shutdown_request(request)
17         except:
18             self.handle_error(request, client_address)
19             self.shutdown_request(request)
20 
21     def process_request(self, request, client_address):
22         """Start a new thread to process the request."""
23         t = threading.Thread(target = self.process_request_thread,
24                              args = (request, client_address))
25         t.daemon = self.daemon_threads
26         t.start()
27 
28 ThreadingMixIn

ThreadingMixIn
威尼斯网址开户网站 25

1 class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

ThreadingTCPServer

RequestHandler相关源码

威尼斯网址开户网站 26

class BaseRequestHandler:

    """Base class for request handler classes.

    This class is instantiated for each request to be handled.  The
    constructor sets the instance variables request, client_address
    and server, and then calls the handle() method.  To implement a
    specific service, all you need to do is to derive a class which
    defines a handle() method.

    The handle() method can find the request as self.request, the
    client address as self.client_address, and the server (in case it
    needs access to per-server information) as self.server.  Since a
    separate instance is created for each request, the handle() method
    can define arbitrary other instance variariables.

    """

    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        self.setup()
        try:
            self.handle()
        finally:
            self.finish()

    def setup(self):
        pass

    def handle(self):
        pass

    def finish(self):
        pass

SocketServer.BaseRequestHandler

SocketServer.BaseRequestHandler

实例:

威尼斯网址开户网站 27

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import SocketServer
 4 
 5 class MyServer(SocketServer.BaseRequestHandler):
 6 
 7     def handle(self):
 8         # print self.request,self.client_address,self.server
 9         conn = self.request
10         conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
11         Flag = True
12         while Flag:
13             data = conn.recv(1024)
14             if data == 'exit':
15                 Flag = False
16             elif data == '0':
17                 conn.sendall('通过可能会被录音.balabala一大推')
18             else:
19                 conn.sendall('请重新输入.')
20 
21 
22 if __name__ == '__main__':
23     server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
24     server.serve_forever()
25 
26 服务端

server
威尼斯网址开户网站 28

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 
 6 
 7 ip_port = ('127.0.0.1',8009)
 8 sk = socket.socket()
 9 sk.connect(ip_port)
10 sk.settimeout(5)
11 
12 while True:
13     data = sk.recv(1024)
14     print 'receive:',data
15     inp = raw_input('please input:')
16     sk.sendall(inp)
17     if inp == 'exit':
18         break
19 
20 sk.close()
21 
22 客户端

client

源码精简:

import socket
import threading
import select


def process(request, client_address):
    print request,client_address
    conn = request
    conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
    flag = True
    while flag:
        data = conn.recv(1024)
        if data == 'exit':
            flag = False
        elif data == '0':
            conn.sendall('通过可能会被录音.balabala一大推')
        else:
            conn.sendall('请重新输入.')

sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.bind(('127.0.0.1',8002))
sk.listen(5)

while True:
    r, w, e = select.select([sk,],[],[],1)
    print 'looping'
    if sk in r:
        print 'get request'
        request, client_address = sk.accept()
        t = threading.Thread(target=process, args=(request, client_address))
        t.daemon = False
        t.start()

sk.close()

如精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

ForkingTCPServer

ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者建立
“线程”  和 “进程”。

基本使用:

威尼斯网址开户网站 29

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import SocketServer
 4 
 5 class MyServer(SocketServer.BaseRequestHandler):
 6 
 7     def handle(self):
 8         # print self.request,self.client_address,self.server
 9         conn = self.request
10         conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
11         Flag = True
12         while Flag:
13             data = conn.recv(1024)
14             if data == 'exit':
15                 Flag = False
16             elif data == '0':
17                 conn.sendall('通过可能会被录音.balabala一大推')
18             else:
19                 conn.sendall('请重新输入.')
20 
21 
22 if __name__ == '__main__':
23     server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyServer)
24     server.serve_forever()
25 
26 服务端

服务端
威尼斯网址开户网站 30

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 
 6 
 7 ip_port = ('127.0.0.1',8009)
 8 sk = socket.socket()
 9 sk.connect(ip_port)
10 sk.settimeout(5)
11 
12 while True:
13     data = sk.recv(1024)
14     print 'receive:',data
15     inp = raw_input('please input:')
16     sk.sendall(inp)
17     if inp == 'exit':
18         break
19 
20 sk.close()
21 
22 客户端

客户端

以上ForkingTCPServer只是将 ThreadingTCPServer 实例中的代码:

server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyRequestHandler)
变更为:
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyRequestHandler)

SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 os.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

 

IO多路复用

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

Linux

Linux中的 select,poll,epoll 都是IO多路复用的机制。

威尼斯网址开户网站 31

 1 select
 2 
 3 select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些
 4 文件描述符从而进行后续的读写操作。
 5 select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
 6 select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
 7 另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()
 8 会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
 9 
10 poll
11 
12 poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
13 poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
14 另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,
15 这种方式称为水平触发(Level Triggered)。
16 
17 epoll
18 
19 直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
20 epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),
21 理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
22 epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中
23 依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。
24 另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个
25 文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

View Code

Python

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

Windows Python:
    提供: select
Mac Python:
    提供: select
Linux Python:
    提供: select、poll、epoll

注意:网络操作、文件操作、终端操作等均属于IO操作,对于windows只支持Socket操作,其他系统支持其他IO操作,但是无法检测
普通文件操作 自动上次读取是否已经变化。

对于select方法:

句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)

参数: 可接受四个参数(前三个必须)
返回值:三个列表

select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
   当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

利用select监听多端口实例:

import socket

sk1 = socket.socket()
sk1.bind(('127.0.0.1',8001))
sk1.listen()

sk2 = socket.socket()
sk2.bind(('127.0.0.1',8002))
sk2.listen()

sk3 = socket.socket()
sk3.bind(('127.0.0.1',8003))
sk3.listen()

inputs = [sk1,sk2,sk3]
import select

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

    #当sk1,sk2,sk3其中有哪个有错误的时候,就将哪个给移除
    for sk in e_list:
        inputs.remove(sk)

威尼斯网址开户网站 32

 1 import socket
 2 sk1 = socket.socket()
 3 sk1.bind(('127.0.0.1',8001))
 4 sk1.listen()
 5 
 6 inputs = [sk1,]
 7 import select
 8 
 9 while True:
10     # [sk1,sk2,sk3]内部自动监听sk1,sk2,sk3三个对象,一旦某个句柄发生变化
11     # 如果有人连接sk1  ->  r_list = [sk1]
12     # 如果有人第一次连接,sk1发生变化
13     r_list,w_list,e_list = select.select(inputs,[],inputs,1)
14 
15     print('正在监听的socket对象%d'% len(inputs))
16     print(r_list)
17     for sk1_or_conn in r_list:
18         # 每一个连接对象
19         if sk1_or_conn == sk1:
20             # sk==sk1 表示有新用户来连接了
21             conn,address = sk1_or_conn.accept()
22             inputs.append(conn)
23         else:
24             # 有老用户发消息来了
25             try:
26                 data_bytes = sk1_or_conn.recv(1024)
27                 data_str = str(data_bytes,encoding='utf-8')
28                 sk1_or_conn.sendall(bytes(data_str+'好',encoding='utf-8'))
29             except Exception as ex:
30                 inputs.remove(sk1_or_conn)

利用select实现伪同时处理多个Socket客户端请求:服务端
威尼斯网址开户网站 33

 1 import socket
 2 sk1 = socket.socket()
 3 sk1.bind(('127.0.0.1',8001))
 4 sk1.listen()
 5 
 6 inputs = [sk1,]
 7 outputs = []
 8 message_dict = {}
 9 
10 import select
11 
12 while True:
13     r_list,w_list,e_list = select.select(inputs,outputs,inputs,1)
14     print('正在监听的socket对象%d'% len(inputs))
15     print(r_list)
16     # 这个for循环只用于处理接收
17     for sk1_or_conn in r_list:
18         # 每一个连接对象
19         if sk1_or_conn == sk1:
20             # sk==sk1 表示有新用户来连接了
21             conn,address = sk1_or_conn.accept()
22             inputs.append(conn)
23             message_dict[conn] = []
24         else:
25             # 有老用户发消息来了
26             try:
27                 data_bytes = sk1_or_conn.recv(1024)
28             except Exception as ex:
29                 print(ex)
30                 inputs.remove(sk1_or_conn)
31             else:
32                 #用户正常发送消息
33                 data_str = str(data_bytes,encoding='utf-8')
34                 message_dict[sk1_or_conn].append(data_str)
35 
36                 outputs.append(sk1_or_conn)
37     # 这个for循环用户处理发送信息
38     # w_list仅仅保存了谁给我发过消息
39     for conn in w_list:
40         recv_str = message_dict[conn][0]
41         del message_dict[conn][0]
42         conn.sendall(bytes(recv_str+'好',encoding='utf-8'))
43         outputs.remove(conn)

利用select实现伪同时处理多个Socket客户端请求:服务端优化版

 

本节总结

一:socket,服务端同时只能处理一个请求

二:select + socket,伪并发

  a : r_list  既读又写

  b : r_list , w_list 读写分离

三:socketserver

  select/epoll + socket + 多线程    真正实现多并发操作

什么是客户/服务器架构?
什么是客户/服务器架构?不同的人有不同的答案。这要看你…

相关文章