python下的socket学习,包括select, epoll,kqueue

服务端:

    基本思路生成socket,绑定IP端口,listen后使用select或者kqueue管理链接是否可以读写操作。获得链接后,等待客户端输入,将从客户端收到的数据原样返回给客户端。实现基本的回显操作。


服务端代码:

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()



转载于:https://my.oschina.net/u/2299936/blog/615252

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值