VII Python(9)socket编程
VII Python(9)socket編程
?
socket編程:
網(wǎng)絡(luò)基礎(chǔ);
TCP/IP;
socket模型;
python socket C/S開發(fā);
非阻塞(select、poll、epoll)
?
網(wǎng)絡(luò)基礎(chǔ):
?
OSI七層協(xié)議、TCP/IP分層
注:
物理層(數(shù)據(jù)之間比特流的傳輸、物理接口、電氣特性;硬件接口標(biāo)準(zhǔn),如RJ45水晶頭、無線網(wǎng)絡(luò)傳輸802.11b等);
數(shù)據(jù)鏈路層(組幀,進(jìn)行硬件地址尋址,差錯(cuò)校驗(yàn)等功能;ARP、RARP;單個(gè)鏈路上數(shù)據(jù)的傳輸,如傳輸依賴的是光纖、雙絞線、還是無線等方式);
網(wǎng)絡(luò)層(進(jìn)行邏輯地址尋址,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路由選擇;ICMP、IP、IGMP;定義了端到端包的封裝方式,分片傳輸,如物理層的傳輸媒介傳輸單元的大小控制(通常網(wǎng)卡屬性上有單元大小,一般默認(rèn)是1460長度一個(gè)單位),還定義了網(wǎng)絡(luò)中節(jié)點(diǎn)的邏輯位置(邏輯坐標(biāo)));
傳輸層(可靠與不可靠傳輸,傳輸前的錯(cuò)誤檢測、流控;TCP、UDP;網(wǎng)絡(luò)中數(shù)據(jù)的傳輸和控制,如tcp有連接狀態(tài),保證數(shù)據(jù)傳輸無差錯(cuò),udp無連狀態(tài),終端A只發(fā)送不管終端B是否收到,負(fù)責(zé)處理整個(gè)數(shù)據(jù)流拆成多個(gè)包時(shí)組裝次序的過程);
會(huì)話層(建立、管理、中止會(huì)話;決定了如何控制開始和結(jié)束的端對端的會(huì)話);
表示層(數(shù)據(jù)的表示、安全、壓縮;定義傳輸?shù)臄?shù)據(jù)格式,ASCII還是binary方式);
應(yīng)用層(用戶接口;計(jì)算機(jī)中通信的具體應(yīng)用,如Email、httpd等);
?
TCP三次握手、四次揮手:
TCP finite statemachine(FSM):
注:
CLOSED(there is no connection);
LISTEN(passive openreceived;waiting for SYN);
SYN-SENT(SYN sent;waiting forACK);
SYN-RCVD(SYN+ACK sent;waiting forACK);
ESTABLISHED(connectionestablished;data transfer in progress);
FIN-WAIT1(first FIN sent;waiting forACK);
FIN-WAIT2(ACK to first FINreceived;waiting for second FIN);
CLOSE-WAIT(first FIN received,ACK sent;waiting forapplication to close);
TIME-WAIT(second FIN received,ACK sent;waiting for2MSL(maximum segment lifetime,120s) timeout);
LAST-ACK(seconf FIN sent;waiting forACK);
CLOSING(both sides havedecided to close simultaneously)
?
?
socket C/S模式網(wǎng)絡(luò)開發(fā):
網(wǎng)絡(luò)中不同主機(jī)間進(jìn)程的交互;
client connect() 連接server-side時(shí)會(huì)隨機(jī)用一個(gè)port號(hào);
socket套接字,用于描述IP:PORT,是一個(gè)通信鏈的句柄handler,應(yīng)用程序通常通過socket向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求;socket起源于Unix,而Unix/Linux基本哲學(xué)之一是“一切皆文件”,對于文件用“打開、讀寫、關(guān)閉”模式來操作,socket就是該模式的一個(gè)體現(xiàn),即是一種特殊的文件,一些socket函數(shù)就是對其進(jìn)行的“r/wIO、打開、關(guān)閉”);
socket和file的區(qū)別(file是針對某個(gè)指定的文件進(jìn)行“打開、讀寫、關(guān)閉”;而socket是針對server-side和client-side進(jìn)行“打開、讀寫、關(guān)閉”);
?
?
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)? ?#(創(chuàng)建對象)
參數(shù)一,地址簇:
AF_INET為ipv4地址;
AF_INET6為ipv6地址;
AF_UNIX只能用于單一的Unix系統(tǒng)連接;
參數(shù)二,類型:
SOCK_STREAM指tcp協(xié)議默認(rèn);
SOCK_DGRAM指udp;
SOCK_RAW原始套接字,普通的套接字無法處理ICMP、IGMP等網(wǎng)絡(luò)報(bào)文,而SOCK_RAW可以,而且SOCK_RAW也可處理特殊的IPv4報(bào)文,另利用原始套接字,可通過IP_HDRINCL套接字選項(xiàng)由用戶構(gòu)造IP頭;
參數(shù)三,協(xié)議:
0(默認(rèn),與特定的家族相關(guān)的協(xié)議,若是0系統(tǒng)會(huì)根據(jù)地址格式和套接類別自動(dòng)選擇一個(gè)合適的協(xié)議);
?
sock.setblocking(bool)?? #(是否blocking,默認(rèn)為True,如果設(shè)置False那accept和recv時(shí)一旦無數(shù)據(jù)則會(huì)報(bào)錯(cuò))
?
sock.setsockopt(level,option,value)?? #(設(shè)置套接字選項(xiàng),level是被設(shè)置的選項(xiàng)的級(jí)別,若要想在套接字上設(shè)置level必須為SOL_SOCKET,在此級(jí)別下option有眾多選項(xiàng)其中SO_REUSEADDR表示打開或關(guān)閉地址利用功能,value為0表示關(guān)閉,非0打開;SO_DEBUG表示打開或關(guān)閉調(diào)試信息;SO_DONTROUTE表示打開或關(guān)閉路由查找功能;SO_BROADCAST表示允許或禁止發(fā)送廣播數(shù)據(jù);SO_SNDBUF設(shè)置發(fā)送緩沖區(qū)的大小,有上下限,下限為2048byte,上限為256*(size of (struct sk_buff)+256))
?
sock.bind(address)?? #(將套接字綁定到地址,address的格式取決于地址族,在AF_INET下,以tuple的形式表示地址(IP,port))
?
sock.listen(backlog)?? #(開始監(jiān)聽傳入連接,backlog指定在拒絕連接之前可以掛起的最大連接數(shù)量,backlog若為5表示內(nèi)核已經(jīng)接到了連接請求,但服務(wù)器還沒有調(diào)用accept進(jìn)行處理的連接個(gè)數(shù)最大為5,這個(gè)值不能無限大,因?yàn)橐趦?nèi)核中維護(hù)連接隊(duì)列)
?
sock.accept()?? #(接受連接并返回(conn,address),其中conn是新的套接字對象,可以用來接收和發(fā)送數(shù)據(jù),address是連接client的地址,接收tcp client的連接以blocking阻塞式等待連接的到來)
?
sock.recv(bufsize[,flag])?? #(接收套接字的數(shù)據(jù),數(shù)據(jù)以字符串形式返回,bufsize指定最多可以接收的數(shù)量,flag提供有關(guān)消息的其它信息,通常可忽略)
?
sock.recvfrom(bufsize[,flag])?? #(與sock.recv(bufsize[,flag])類似,不過另有返回值(data,address),data是包含接收數(shù)據(jù)的字符串,address是發(fā)送數(shù)據(jù)的套接字地址)
?
sock.send(string[,flag])?? #(將數(shù)據(jù)string發(fā)送到連接的套接字,返回值是要發(fā)送的字節(jié)數(shù)量,該數(shù)量可能小于string的字節(jié)大小即可能未將指定內(nèi)容全部發(fā)送)
?
sock.sendall(string[,flag])?? #(將數(shù)據(jù)string發(fā)送到連接的套接字,但在返回之前會(huì)嘗試發(fā)送所有數(shù)據(jù),成功返回None,失敗則會(huì)拋出異常)
?
sock.sendto(string[,flag],address)?? #(將數(shù)據(jù)string發(fā)送到套接字,address的形式是(ip,port)的tuple,指定遠(yuǎn)程地址,返回值是發(fā)送的字節(jié)數(shù),該函數(shù)主要用于udp協(xié)議)
?
sock.close()?? #(關(guān)閉套接字)
?
sock.connect(address)?? #(連接到address處的套接字,一般address的格式為tuple,(IP orhostname,port),如果連接出錯(cuò),返回socket.error錯(cuò)誤)
?
sock.connect_ex(address)?? #(與sock.connect(address)功能相同,只不過多了返回值,連接成功時(shí)返回0,連接失敗時(shí)返回非0編碼,例如10061)
?
sock.settimeout(timeout)? ?#(設(shè)置套接字操作的超時(shí)期timeout是一個(gè)浮點(diǎn)數(shù),單位秒,值為None表示沒有超時(shí)期,一般超時(shí)期應(yīng)在剛創(chuàng)建套接字時(shí)設(shè)置,因?yàn)樗鼈兛赡苡糜谶B接的操作,例如client連接時(shí)最多等待5s)
?
sock.getpeername()?? #(返回連接套接字的遠(yuǎn)程地址,返回值通常是tuple(ip,port))
?
sock.getsockname()?? #(返回套接字自己的地址,通常是tuple(ip,port))
?
sock.fileno()?? #(套接字的文件描述符fd)
?
?
socket高級(jí)應(yīng)用,IO多路復(fù)用(指通過一種機(jī)制可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(一般是讀就緒或?qū)懢途w),能夠通知程序進(jìn)行相應(yīng)的讀寫操作);Linux中的select、poll、epoll都是IO多路復(fù)用的機(jī)制):
select(通過select()系統(tǒng)調(diào)用來監(jiān)視多個(gè)文件描述符的數(shù)組,當(dāng)select返回后,該數(shù)組中就緒的文件描述符便會(huì)被內(nèi)核修改標(biāo)志位,使得進(jìn)程可以獲得這些文件描述符從而進(jìn)行后續(xù)的讀寫操作;此策略的缺點(diǎn),單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,Linux默認(rèn)為1024,隨著文件描述符數(shù)量的增大,其復(fù)制的開銷也線性增長);
poll(與select類似,但沒有文件描述符的限制);
epoll(內(nèi)核直接支持,基于事件驅(qū)動(dòng)event-driven(分兩部分:注冊事件和觸發(fā)事件);
?
Python中有select模塊,該模塊提供了select、poll、epoll這三種方法)
?
rs,ws,xs=select.select(rlist,wlist,xlist[,timeout])?? #(select方法用來監(jiān)視文件句柄,如果句柄發(fā)生變化,則獲取該句柄;括號(hào)中前三個(gè)參數(shù)必須,返回三個(gè)列表)
當(dāng)rlist中的句柄發(fā)生可讀時(shí)(accept和read),則獲取發(fā)生變化的句柄并添加到rs中;
當(dāng)wlist中含有句柄時(shí),則將該序列中所有的句柄添加到ws中;
當(dāng)xlist中的句柄發(fā)生錯(cuò)誤時(shí),則將該發(fā)生錯(cuò)誤的句柄添加到xs中;
當(dāng)timeout未設(shè)置select會(huì)一直blocking,直到監(jiān)聽的句柄發(fā)生變化;當(dāng)timeout為1時(shí),如果監(jiān)聽的句柄無任何變化則select會(huì)阻塞1s之后返回三個(gè)空列表,如果監(jiān)聽的句柄有變化則直接執(zhí)行;
?
?
In [1]: import socket
In [2]: help(socket)
Functions:
???socket() -- create a new socket object
???socketpair() -- create a pair of new socket objects [*]
???fromfd() -- create a socket object from an open file descriptor [*]
???gethostname() -- return the current hostname
???gethostbyname() -- map a hostname to its IP number
???gethostbyaddr() -- map an IP number or hostname to DNS info
???getservbyname() -- map a service name and a protocol name to a portnumber
???getprotobyname() -- map a protocol name (e.g. 'tcp') to a number
???ntohs(), ntohl() -- convert 16, 32 bit int from network to host byteorder
???htons(), htonl() -- convert 16, 32 bit int from host to network byteorder
???inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packedformat
???inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)
???ssl() -- secure socket layer support (only available if configured)
???socket.getdefaulttimeout() -- get the default timeout value
???socket.setdefaulttimeout() -- set the default timeout value
???create_connection() -- connects to an address, with an optional timeoutand
?????????????????????????? optional sourceaddress.
In [3]: print dir(socket)
['AF_APPLETALK', 'AF_ASH', 'AF_ATMPVC','AF_ATMSVC', 'AF_AX25', 'AF_BRIDGE', 'AF_DECnet', 'AF_ECONET', 'AF_INET', 'AF_INET6','AF_IPX',……'PACKET_OUTGOING', 'PF_PACKET', 'RAND_add', 'RAND_egd','RAND_status', 'SHUT_RD', 'SHUT_RDWR', 'SHUT_WR', 'SOCK_DGRAM','SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM','SOL_IP', 'SOL_SOCKET', 'SOL_TCP', 'SOL_TIPC', 'SOL_UDP', 'SOMAXCONN', ……'create_connection','errno', 'error', 'fromfd', 'gaierror', 'getaddrinfo', 'getdefaulttimeout','getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostbyname_ex', 'gethostname','getnameinfo', 'getprotobyname', 'getservbyname', 'getservbyport', 'has_ipv6','herror', 'htonl', 'htons', 'inet_aton', 'inet_ntoa', 'inet_ntop', 'inet_pton','m', 'meth', 'ntohl', 'ntohs', 'os', 'p', 'partial', 'setdefaulttimeout', 'socket', 'socketpair', 'ssl', 'sslerror', 'sys','timeout', 'warnings']
In [4]: sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)??#(創(chuàng)建對象;參數(shù)一地址簇:AF_INET為ipv4地址,AF_INET6為ipv6地址,AF_UNIX只能用于單一的Unix系統(tǒng)連接;參數(shù)二類型:SOCK_STREAM指tcp協(xié)議默認(rèn),SOCK_DGRAM指udp)
In [5]: print dir(sock)
['__class__', '__delattr__', '__doc__','__format__', '__getattribute__', '__hash__', '__init__', '__module__','__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__','__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__','_sock', 'accept', 'bind', 'close', 'connect', 'connect_ex','dup', 'family', 'fileno', 'getpeername', 'getsockname', 'getsockopt','gettimeout', 'listen', 'makefile', 'proto', 'recv', 'recv_into', 'recvfrom', 'recvfrom_into', 'send', 'sendall', 'sendto', 'setblocking','setsockopt', 'settimeout', 'shutdown', 'type']
In [6]: help(sock.bind)?? #(server-side使用,對象綁定)
bind(...) method of socket._socketobjectinstance
???bind(address)
???Bind the socket to a local address.?For IP sockets, the address is a
???pair (host, port); the host must refer to the local host. For raw packet
???sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])
In [7]: help(sock.listen)?? #(server-side使用,指定監(jiān)聽多少個(gè)請求)
listen(...) method of socket._socketobjectinstance
???listen(backlog)
???Enable a server to accept connections.?The backlog argument must be at
???least 0 (if it is lower, it is set to 0); it specifies the number of
???unaccepted connections that the system will allow before refusing new
???connections.
In [8]: help(sock.accept)??#(server-side使用,sock.accpet()返回兩個(gè)參數(shù),一個(gè)是建立連接的socket object和另一個(gè)是地址信息)
accept(self) method of socket._socketobjectinstance
???accept() -> (socket object, address info)
???Wait for an incoming connection.?Return a new socket representing the
???connection, and the address of the client.? For IP sockets, the address
???info is a pair (hostaddr, port).
In [9]:help(sock.recv) ??#(設(shè)置讀操作緩沖區(qū)大小,server-side和client-side都可使用,注意server-side使用時(shí)此項(xiàng)要在socket.accept()返回的那個(gè)socketobject上使用)
recv(...)
???recv(buffersize[, flags]) -> data
???Receive up to buffersize bytes from the socket.? For the optional flags
???argument, see the Unix manual.?When no data is available, block until
???at least one byte is available or until the remote end is closed.? When
???the remote end is closed and all data is read, return the empty string.
In [10]:help(sock.send) ??#(寫操作,server-side和client-side均可使用,注意server-side使用時(shí)要在socket.accept()返回的那個(gè)socketobject上使用)
send(...)
???send(data[, flags]) -> count
???Send a data string to the socket.?For the optional flags
???argument, see the Unix manual.?Return the number of bytes
???sent; this may be less than len(data) if the network is busy.
In [11]: help(sock.close)??#(server-side和client均可使用)
close(self, _closedsocket=<class'socket._closedsocket'>, _delegate_methods=('recv', 'recvfrom', 'recv_into','recvfrom_into', 'send', 'sendto'), setattr=<built-in function setattr>)method of socket._socketobject instance
???close()
???Close the socket.? It cannot beused after this call.
In [12]: help(sock.connect)?? #(用于client)
connect(...) method of socket._socketobjectinstance
???connect(address)
???Connect the socket to a remote address.?For IP sockets, the address
???is a pair (host, port).
In [13]: help(sock.getpeername)??#(用于client,返回連接的服務(wù)器地址)
getpeername(...) method ofsocket._socketobject instance
???getpeername() -> address info
???Return the address of the remote endpoint.? For IP sockets, the address
???info is a pair (hostaddr, port).
?
In [14]: help(sock.setblocking)?? #(server-side用,flag為false則是non-blocking,flag為True則是blocking)
setblocking(...) method ofsocket._socketobject instance
???setblocking(flag)
???Set the socket to blocking (flag is true) or non-blocking (false).
???setblocking(True) is equivalent to settimeout(None);
???setblocking(False) is equivalent to settimeout(0.0).
In [15]: help(sock.setsockopt)??#(server-side用)
setsockopt(...) method ofsocket._socketobject instance
???setsockopt(level, option, value)
???Set a socket option.? See the Unixmanual for level and option.
???The value argument can either be an integer or a string.
?
In [16]: import select
In [17]: print dir(select)
['EPOLLERR', 'EPOLLET', 'EPOLLHUP','EPOLLIN', 'EPOLLMSG', 'EPOLLONESHOT', 'EPOLLOUT', 'EPOLLPRI', 'EPOLLRDBAND','EPOLLRDNORM', 'EPOLLWRBAND', 'EPOLLWRNORM', 'PIPE_BUF', 'POLLERR', 'POLLHUP','POLLIN', 'POLLMSG', 'POLLNVAL', 'POLLOUT', 'POLLPRI', 'POLLRDBAND','POLLRDNORM', 'POLLWRBAND', 'POLLWRNORM', '__doc__', '__file__', '__name__','__package__', 'epoll', 'error', 'poll', 'select']
In [18]: help(select)
NAME
???select - This module supports asynchronous I/O on multiple filedescriptors.
FUNCTIONS
???poll(...)
???????Returns a polling object, which supports registering and
???????unregistering file descriptors, and then polling them for I/O events.
???select(...)
???????select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)
???????Wait until one or more file descriptors are ready for some kind of I/O.
???????The first three arguments are sequences of file descriptors to be waitedfor:
???????rlist -- wait until ready for reading
???????wlist -- wait until ready for writing
???????xlist -- wait for an ``exceptional condition''
???????If only one kind of condition is required, pass [] for the other lists.
???????A file descriptor is either a socket or file object, or a small integer
???????gotten from a fileno() method call on one of those.
???????The optional 4th argument specifies a timeout in seconds; it may be
???????a floating point number to specify fractions of seconds.? If it is absent
???????or None, the call will never time out.
???????The return value is a tuple of three lists corresponding to the firstthree
???????arguments; each contains the subset of the corresponding filedescriptors
???????that are ready.
?
In [19]: import Queue
In [20]: help(Queue)
NAME
???Queue - A multi-producer, multi-consumer queue.
???class Queue
????|? Create a queue object with agiven maximum size.
????|? get(self, block=True,timeout=None)
????|????? Remove and return an itemfrom the queue.
????|????? If optional args 'block' istrue and 'timeout' is None (the default),
????|????? block if necessary until anitem is available. If 'timeout' is
????|????? a non-negative number, itblocks at most 'timeout' seconds and raises
????|????? the Empty exception if noitem was available within that time.
????|????? Otherwise ('block' isfalse), return an item if one is immediately
????|????? available, else raise theEmpty exception ('timeout' is ignored
????|????? in that case).
????|? get_nowait(self)
????|????? Remove and return an itemfrom the queue without blocking.
????|?????
????|? ????Only get an item if one is immediatelyavailable. Otherwise
????|????? raise the Empty exception.
????|? put(self, item, block=True,timeout=None)
????|????? Put an item into the queue.
????|????? If optional args 'block' istrue and 'timeout' is None (the default),
????|????? block if necessary until afree slot is available. If 'timeout' is
????|????? a non-negative number, itblocks at most 'timeout' seconds and raises
????|????? the Full exception if nofree slot was available within that time.
????|????? Otherwise ('block' isfalse), put an item on the queue if a free slot
????|????? is immediately available,else raise the Full exception ('timeout'
????|????? is ignored in that case).
????|? put_nowait(self, item)
????|????? Put an item into the queuewithout blocking.
????|????? Only enqueue the item if afree slot is immediately available.
????|????? Otherwise raise the Fullexception.
In [21]: print dir(Queue)
['Empty', 'Full', 'LifoQueue','PriorityQueue', 'Queue', '__all__','__builtins__', '__doc__', '__file__', '__name__', '__package__', '_threading','_time', 'deque', 'heapq']
In [22]: print dir(Queue.Queue)
['__doc__', '__init__', '__module__','_get', '_init', '_put', '_qsize', 'empty', 'full', 'get','get_nowait', 'join', 'put', 'put_nowait','qsize', 'task_done']
?
?
舉例-version1(使用socket模塊實(shí)現(xiàn)C/S通信)
[root@localhost ~]# vim server_test.py
----------------script start-----------------
#!/usr/bin/python2.7
#
import socket
?
server=('10.96.20.113',20072)
?
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(server)
sock.listen(5)
conn,address=sock.accept()
print 'connect by',address
while True:
???????data=conn.recv(1024)
???????if not data: break
???????print data
???????conn.send(data)
sock.close()
--------------------script end-----------------
[root@localhost ~]# vim client_test.py
--------------------script start---------------
#!/usr/bin/python2.7
#
import socket
?
server=('10.96.20.113',20072)
?
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(server)
sock.send('hello')
data=sock.recv(1024)
print 'echo',data
sock.close()
---------------------script end------------------
[root@localhost ~]# python2.7 server_test.py ??#(分別在兩個(gè)終端上運(yùn)行server-side和client-side)
connect by ('10.96.20.113', 48273)
hello
[root@localhost ~]# python2.7 client_test.py
echo hello
?
舉例-version2(使用socket模塊實(shí)現(xiàn)C/S通信)
[root@localhost ~]# vim client_test.py ??#(服務(wù)端與version1相同,只更改client)
-------------------script start-----------------
#!/usr/bin/python2.7
#
import socket
import time
?
server=('10.96.20.113',20072)
msg=['hello','everyone','welcome','to','my','territory']
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(server)
for m in msg:
? ? ? ?sock.send(m)
???????data=sock.recv(1024)
???????print 'echo',data
???????time.sleep(2)
sock.close
-----------------------script end-----------------
[root@localhost ~]# python2.7 server_test.py ??#(分別在兩個(gè)窗口上運(yùn)行server_test.py和client_test.py)
connect by ('10.96.20.113', 48275)
hello
everyone
welcome
to
my
territory
[root@localhost ~]# python2.7 client_test.py
echo hello
echo everyone
echo welcome
echo to
echo my
echo territory
[root@localhost ~]# python2.7 client_test.py ??#(再次運(yùn)行client,由于server-side已不在運(yùn)行,窗口已關(guān)閉,client運(yùn)行時(shí)Connectionrefused拒絕連接)
Traceback (most recent call last):
?File "client_test.py", line 9, in <module>
???sock.connect(server)
?File "/usr/local/python2.7/lib/python2.7/socket.py", line 224,in meth
???return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused
注:server-side不支持并發(fā)操作不能作為永久的伺服器;server-side沒有讀寫分離(I/O輸入輸出分離),有分離的話會(huì)提高并發(fā)能力
?
?
舉例(利用select模塊實(shí)現(xiàn)處理多個(gè)client請求)
[root@localhost ~]# vim server_test.py
-------------------script start--------------
#!/usr/bin/python2.7
#
import socket
import select
import Queue
?
server=('10.96.20.113',20072)
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setblocking(False)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sock.bind(server)
sock.listen(10)
rlists=[sock]
wlists=[]
msg_que={}
timeout=20
while rlists:
???????rs,ws,es=select.select(rlists,wlists,rlists,timeout)
???????if not (rs or ws or es):
??????????????? print 'timeout...'
??????????????? break
???????for s in rs:
??????????????? if s is sock:
??????????????????????? conn,addr=s.accept()
??????????????????????? print 'connect by',addr
??????????????????????? conn.setblocking(False)
??????????????????????? rlists.append(conn)
???????????????????????msg_que[conn]=Queue.Queue()
???????????????else:
??????????????????????? data=s.recv(1024)
??????????????????????? if data:
??????????????????????????????? print data
???????????????????????????????msg_que[s].put(data)
??????????????????????????????? if s not inwlists:
???????????????????????????????????????wlists.append(s)
??????????????????????? else:
??????????????????????????????? if s in wlists:
???????????????????????????????????????wlists.remove(s)
???????????????????????????????rlists.remove(s)
?????????????? ?????????????????s.close()
??????????????????????????????? del msg_que[s]
???????for s in ws:
??????????????? try:
???????????????????????msg=msg_que[s].get_nowait()
??????????????? except Queue.Empty:
??????????????????????? print 'msg empty'
???????????????????????wlists.remove(s)
??????????????? else:
??????????????????????? s.send(msg)
???????for s in es:
??????????????? print 'except',s.getpeername()
??????????????? if s in rlists:
??????????????????????? rlists.remove(s)
??????????????? if s in wlists:
??????????????????????? wlists.remove(s)
??????????????? s.close()
??????????????? del msg_que[s]
--------------------script end----------------
[root@localhost ~]# vim client_test.py
----------------------script start----------------
#!/usr/bin/python2.7
#
import socket
import time
?
server=('10.96.20.113',20072)
msg=['hello','everyone','welcome','to','my','territory']
socks=[]
?
for i in range(10):
???????sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
???????socks.append(sock)
for s in socks:
???????s.connect(server)
counter=0
for m in msg:
???????for s in socks:
??????????????? s.send('%d send %s' %(counter,m))
??????????????? counter+=1
???????for s in socks:
??????????????? data=s.recv(1024)
??????????????? print '%s echo %s' % (s.getpeername(),data)
??????????????? if not data:
??????????????????????? s.close()
???????time.sleep(2)
---------------------script end--------------------
[root@localhost ~]# python2.7 server_test.py ??#(在兩個(gè)終端上分別執(zhí)行server_test.py和client_test.py)
connect by ('10.96.20.113', 48299)
connect by ('10.96.20.113', 48300)
connect by ('10.96.20.113', 48301)
connect by ('10.96.20.113', 48302)
connect by ('10.96.20.113', 48303)
connect by ('10.96.20.113', 48304)
connect by ('10.96.20.113', 48305)
connect by ('10.96.20.113', 48306)
connect by ('10.96.20.113', 48307)
connect by ('10.96.20.113', 48308)
……
58 send territory
59 send territory
……
msg empty
msg empty
msg empty
timeout...
[root@localhost ~]# python2.7 client_test.py
('10.96.20.113', 20072) echo 0 send hello
('10.96.20.113', 20072) echo 1 send hello
('10.96.20.113', 20072) echo 2 send hello
('10.96.20.113', 20072) echo 3 send hello
('10.96.20.113', 20072) echo 4 send hello
('10.96.20.113', 20072) echo 5 send hello
('10.96.20.113', 20072) echo 6 send hello
('10.96.20.113', 20072) echo 7 send hello
('10.96.20.113', 20072) echo 8 send hello
('10.96.20.113', 20072) echo 9 send hello
('10.96.20.113', 20072) echo 10 sendeveryone
……
('10.96.20.113', 20072) echo 57 sendterritory
('10.96.20.113', 20072) echo 58 sendterritory
('10.96.20.113', 20072) echo 59 sendterritory
轉(zhuǎn)載于:https://blog.51cto.com/jowin/1834189
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的VII Python(9)socket编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 部分机型GridView
- 下一篇: 装饰器模式与java.io包