python下的socket學習,包括select, epoll,kqueue

服務端:

    基本思路生成socket,綁定IP端口,listen後使用select或者kqueue管理連接是否能夠讀寫操做。得到連接後,等待客戶端輸入,將從客戶端收到的數據原樣返回給客戶端。實現基本的回顯操做。python


服務端代碼:緩存

select模式

# coding=utf-8
__author__ = 'chenglp'

"""socket,select, kqueue學習
"""

import socket
import select
import sys


HOST = '127.0.0.1'
PORT = 8001
BUFFER_SIZE = 1024

#生成socket,綁定ip端口
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM,)
server.bind((HOST, PORT))

server.listen(5)

#建立輸入監聽列表
inputs = [server, sys.stdin]

#select模式
def select_mode():
   running = True
   while running:
      try:
         #select輪詢inputs列表獲取能夠讀的描述符
         readable, writeable, exceptional = select.select(inputs,[],[])
      except select.error as e:
         break

      for each in readable:
         #若是是server,則accept建立連接,並將連接的描述符放入到inputs進行select監聽
         if each == server:
            conn, addr = server.accept()
            inputs.append(conn)
         #若是是系統輸入,則獲取系統輸入,中止程序
         elif each == sys.stdin:
            junk = sys.stdin.readline()
            running = False
         #若是是其它的,則爲socket連接,讀取連接數據,並返回讀取到的數據。
         else:
            try:
               data = each.recv(BUFFER_SIZE)
               if data:
                  each.send(data)
                  if data.endswith('\r\n\r\n'):
                     inputs.remove(each)
                     each.close()
               else:
                  inputs.remove(each)
                  each.close()
            except socket.error as e:
               inputs.remove(each)

   server.close()

epoll模式:

#epoll模式
def epoll_mode():
   running = True
   epoll = select.epoll()

   #註冊epoll讀
   epoll.register(server.fileno(), select.EPOLLIN)
   #保存連接文件描述符和連接的對應關係
   conn_list = {}
   while running:
      try:
         #開始執行epoll
         events = epoll.poll(1)
      except:
         break
      if events:
         for fileno, event in events:
            #若是是新連接,則accept,並將新連接註冊到epoll中
            if fileno == server.fileno():
               conn, addr = server.accept()
               conn.setblocking(0)
               epoll.register(conn.fileno(), select.EPOLLIN)
               conn_list[conn.fileno()] = conn
            #若是是其餘的可讀連接,則獲取到連接,recv數據,若是是\n, 則close,並從epoll中unregister掉這個文件描述符
            elif event == select.EPOLLIN:
               data = conn_list[fileno].recv(BUFFER_SIZE)
               if data.startswith('\n'):
                  conn_list[fileno].close()
                  epoll.unregister(fileno)
                  del(conn_list[fileno])
               else:
                  conn_list[fileno].send(data)

   server.close()

kqueue模式:

#kqueue模式
def kqueue_mode():
   running = True
   kq = select.kqueue()
   conn_list = {}
   index = 1
   #生成kevents列表,監聽socket的讀操做
   events = [
       select.kevent(server.fileno(), select.KQ_FILTER_READ,select.KQ_EV_ADD),
   ]
   while running:
      try:
         #開始kqueue,若是有可執行kevent,則返回對應的kevent列表
         eventlist = kq.control(events,1)
      except select.error as e:
         break
      if eventlist:
         for each in eventlist:
            #若是是socket連接,則accept,將conn建立kevent放入到events進行監聽,將連接放入到conn_list進行保存,key爲index。
            if each.ident == server.fileno():
               conn, addr = server.accept()
               conn_list[index] = conn
               events.append(select.kevent(conn_list[index].fileno(), select.KQ_FILTER_READ, select.KQ_EV_ADD,udata=index))
               index += 1

            else:
               try:
                  #若是不是socket連接,則獲取到conn,而後進行讀寫操做。
                  if each.udata >= 1 and each.flags == select.KQ_EV_ADD and each.filter == select.KQ_FILTER_READ:
                     conn = conn_list[each.udata]
                     data = conn.recv(BUFFER_SIZE)
                     if data.startswith('\n'):
                        conn.close()

                        events.remove(select.kevent(conn_list[each.udata].fileno(), select.KQ_FILTER_READ,
                           select.KQ_EV_ADD,udata=each.udata))
                        del(conn_list[each.udata])
                     else:
                        conn.send(data)
               except:
                  pass

   server.close()

客戶端:

# coding=utf-8
import socket
import select
import sys


HOST = '127.0.0.1'
PORT = 8001
BUFFER_SIZE = 1024


# 建立socket連接,連接服務器
s = socket.socket()
try:
   s.connect((HOST, PORT))
except socket.error as e:
   print e

#建立讀寫監聽列表
readlist = [s, sys.stdin]
writelist = [s, ]
#輸入緩存
writeCache = []

while True:
   try:
      #select監聽獲取可讀可寫
      readable, writeabel, exceptional = select.select(readlist, writelist, [])
   except select.error as e:
      break

   for each in readable:
      #若是是系統輸入,則獲取輸入信息放到輸入緩存裏
      if each == sys.stdin:
         inputs = sys.stdin.readline()
         writeCache.append(inputs)
      #若是是socket,則接受數據
      elif each == s:
         data = s.recv(BUFFER_SIZE)
         print data
      else:
         pass
   for each in writeabel:
      #若是是socket而且寫緩存有數據,則發送數據
      if each == s and writeCache:
         s.sendall(writeCache.pop())
s.close()
相關文章
相關標籤/搜索