Python实现的服务器示例小结【单进程、多进程、多线程、非阻塞式】


Posted in Python onMay 23, 2019

本文实例讲述了Python实现的服务器。分享给大家供大家参考,具体如下:

python - 单进程服务器

#coding=utf-8
from socket import *
#创建套接字
serSocket = socket(AF_INET, SOCK_STREAM)
#重复使用绑定信息
serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
localAddr = ('', 7788)
#绑定端口ip
serSocket.bind(localAddr)
#监听
serSocket.listen(5)
while True:
  print('---主进程,等待新客户端的到来---')
  newSocket,destAddr = serSocket.accept()
  print('---主进程,接下来负责数据处理[%s]---'%str(destAddr))
  try:
    while True:
      recvData = newSocket.recv(1024)
      if len(recvData)>0:
        print('recv[%s]:%s'%(str(destAddr),recvData))
      else:
        print('[%s]客户端已经关闭')
        break
  finally:
    newSocket.close()
serSocket.close()

总结

同一时刻只能为一个客户进行服务,不能同时为多个客户服务。
当服务器为一个客户端服务时,另外的客户端发起了connect,只要服务器listen的队列有空闲的位置,就会为这个新客户端进行连接,并且客户端可以发送数据,但当服务器为这个新客户端服务时,可能一次性把所有数据接收完毕当recv接收数据时,返回值为空,即没有返回数据,那么意味着客户端已经调用了close关闭了;因此服务器通过判断recv接收数据是否为空 来判断客户端是否已经下线。

python - 多进程服务器

#coding=utf-8
from socket import *
from multiprocessing import *
from time import sleep
#处理客户端的请求并为其服务
def dealWithClient(newSocket,destAddr):
  try:
    while True:
      recvData = newSocket.recv(1024)
      if len(recvData) > 0:
        print('recv[%s]:%s' % (str(destAddr), recvData))
      else:
        print('[%s]客户端已经关闭')
        break
  finally:
    newSocket.close()
def main():
  #创建套接字
  serSocket = socket(AF_INET, SOCK_STREAM)
  #重复使用绑定信息
  serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
  localAddr = ('', 7788)
  #绑定端口ip
  serSocket.bind(localAddr)
  #监听
  serSocket.listen(5)
  try:
    while True:
      print('---主进程,等待新客户端的到来---')
      newSocket,destAddr = serSocket.accept()
      print('---主进程,接下来负责数据处理[%s]---'%str(destAddr))
      client = Process(target=dealWithClient, args=(newSocket, destAddr))
      client.start()
      # 因为已经向子进程中copy了一份(引用),并且父进程中这个套接字也没有用处了
      # 所以关闭
      newSocket.close()
  finally:
    # 当为所有的客户端服务完之后再进行关闭,表示不再接收新的客户端的链接
    serSocket.close()
if __name__ == '__main__':
  main()

总结

通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服
务当客户端不是特别多的时候,这种方式还行,如果有成百上千个,就不
可取了,因为每次创建进程的过程需要消耗较多的资源。

python - 多线程服务器

#coding=utf-8
from socket import *
from threading import Thread
from time import sleep
# 处理客户端的请求并执行事情
def dealWithClient(newSocket,destAddr):
  while True:
    recvData = newSocket.recv(1024)
    if len(recvData)>0:
      print('recv[%s]:%s'%(str(destAddr), recvData))
    else:
      print('[%s]客户端已经关闭'%str(destAddr))
      break
  newSocket.close()
def main():
  serSocket = socket(AF_INET, SOCK_STREAM)
  serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)
  localAddr = ('', 7788)
  serSocket.bind(localAddr)
  serSocket.listen(5)
  try:
    while True:
      print('-----主进程,,等待新客户端的到来------')
      newSocket,destAddr = serSocket.accept()
      print('-----主进程,,接下来创建一个新的进程负责数据处理[%s]----'%str(destAddr))
      client = Thread(target=dealWithClient, args=(newSocket,destAddr))
      client.start()
      #因为线程中共享这个套接字,如果关闭了会导致这个套接字不可用,
      #但是此时在线程中这个套接字可能还在收数据,因此不能关闭
      #newSocket.close()
  finally:
    # 当为所有的客户端服务完之后再进行关闭,表示不再接收新的客户端的链接
    serSocket.close()
if __name__ == '__main__':
  main()

单进程服务器-非堵塞模式

服务器:

#coding=utf-8
from socket import *
import time
# 用来存储所有的新链接的socket
g_socketList = []
def main():
  serSocket = socket(AF_INET, SOCK_STREAM)
  serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)
  localAddr = ('', 7788)
  serSocket.bind(localAddr)
  #可以适当修改listen中的值来看看不同的现象
  serSocket.listen(1000)
  #将套接字设置为?堵塞
  #设置为?堵塞后,如果accept时,恰巧没有客户端connect,那么accept会
  #产生一个异常,所以需要try来进行处理
  serSocket.setblocking(False)
  while True:
    #?来测试
    #time.sleep(0.5)
    try:
      newClientInfo = serSocket.accept()
    except Exception as result:
      pass
    else:
      print("一个新的客户端到来:%s"%str(newClientInfo))
      newClientInfo[0].setblocking(False)
      g_socketList.append(newClientInfo)
  # 用来存储需要删除的客户端信息
  needDelClientInfoList = []
  for clientSocket,clientAddr in g_socketList:
    try:
      recvData = clientSocket.recv(1024)
      if len(recvData)>0:
        print('recv[%s]:%s'%(str(clientAddr), recvData))
      else:
        print('[%s]客户端已经关闭'%str(clientAddr))
        clientSocket.close()
        g_needDelClientInfoList.append((clientSocket,clientAddr))
    except Exception as result:
      pass
  for needDelClientInfo in needDelClientInfoList:
    g_socketList.remove(needDelClientInfo)
if __name__ == '__main__':
  main()

客户端:

#coding=utf-8
from socket import *
import random
import time
serverIp = input("请输入服务器的ip:")
connNum = input("请输入要链接服务器的次数(例如1000):")
g_socketList = []
for i in range(int(connNum)):
  s = socket(AF_INET, SOCK_STREAM)
  s.connect((serverIp, 7788))
  g_socketList.append(s)
  print(i)
while True:
  for s in g_socketList:
    s.send(str(random.randint(0,100)))
  # 用来测试
  #time.sleep(1)

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
web.py在模板中输出美元符号的方法
Aug 26 Python
Python实现对比不同字体中的同一字符的显示效果
Apr 23 Python
python使用opencv进行人脸识别
Apr 07 Python
Python制作刷网页流量工具
Apr 23 Python
神经网络python源码分享
Dec 15 Python
python利用微信公众号实现报警功能
Jun 10 Python
详解Python 协程的详细用法使用和例子
Jun 15 Python
对python插入数据库和生成插入sql的示例讲解
Nov 14 Python
Python pycharm 同时加载多个项目的方法
Jan 17 Python
python字典改变value值方法总结
Jun 21 Python
tensorflow常用函数API介绍
Apr 19 Python
Python基于requests实现模拟上传文件
Apr 21 Python
Python3.8中使用f-strings调试
May 22 #Python
总结Python图形用户界面和游戏开发知识点
May 22 #Python
Python闭包和装饰器用法实例详解
May 22 #Python
Python进程间通信Queue消息队列用法分析
May 22 #Python
将python文件打包成EXE应用程序的方法
May 22 #Python
Python多线程threading模块用法实例分析
May 22 #Python
Python3之手动创建迭代器的实例代码
May 22 #Python
You might like
为什么那些咖啡爱好者大多看不上连锁咖啡店?
2021/03/06 咖啡文化
PHP+APACHE实现用户论证的方法
2006/10/09 PHP
仿dedecms下拉分页样式修改的thinkphp分页类实例
2014/10/30 PHP
PHP正则表达式入门教程(推荐)
2016/05/18 PHP
php原生数据库分页的代码实例
2019/02/18 PHP
Yii框架页面渲染操作实例详解
2019/07/19 PHP
分享8个Laravel模型时间戳使用技巧小结
2020/02/12 PHP
javascript 获取url参数和script标签中获取url参数函数代码
2010/01/22 Javascript
JAVASCRIPT style 中visibility和display之间的区别
2010/01/22 Javascript
JavaScript高级程序设计(第3版)学习笔记11 内建js对象
2012/10/11 Javascript
js页面跳转的常用方法整理
2013/10/18 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2013/10/24 Javascript
Javascript中使用parseInt函数需要注意的问题
2015/04/02 Javascript
js下拉选择框与输入框联动实现添加选中值到输入框的方法
2015/08/17 Javascript
在JavaScript中call()与apply()区别
2016/01/22 Javascript
基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解
2016/07/18 Javascript
jquery 实现拖动文件上传加载进度条功能
2018/03/18 jQuery
vue中设置、获取、删除cookie的方法
2018/09/21 Javascript
vue路由跳转传参数的方法
2019/05/06 Javascript
微信小程序自定义可滑动顶部TabBar选项卡实现页面切换功能示例
2019/05/14 Javascript
JavaScript中this的学习笔记及用法整理
2020/02/17 Javascript
Vue 3自定义指令开发的相关总结
2021/01/29 Vue.js
[36:37]2014 DOTA2华西杯精英邀请赛5 24 VG VS iG
2014/05/25 DOTA
跟老齐学Python之赋值,简单也不简单
2014/09/24 Python
Python中判断子串存在的性能比较及分析总结
2019/06/23 Python
python实现数据分析与建模
2019/07/11 Python
利用Tensorboard绘制网络识别准确率和loss曲线实例
2020/02/15 Python
python 用opencv实现霍夫线变换
2020/11/27 Python
css3弹性盒模型实例介绍
2013/05/27 HTML / CSS
财务专业大学生职业生涯规划范文
2013/12/30 职场文书
应届专科生个人的自我评价
2014/01/05 职场文书
大学开学计划书
2014/04/30 职场文书
2014党员整改措施思想汇报
2014/10/07 职场文书
jquery插件实现代码雨特效
2021/04/24 jQuery
浅谈@Value和@Bean的执行顺序问题
2021/06/16 Java/Android
SQL Server远程连接的设置步骤(图文)
2022/03/23 SQL Server