1.单进程服务器

from socket import *

serSocket = socket(AF_INET, SOCK_STREAM)

# 重复使用绑定的信息
serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1) localAddr = ('', 7788) 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]客户端已经关闭'%str(destAddr))
break
finally:
newSocket.close() serSocket.close()

    

 总结

  • 同一时刻只能为一个客户进行服务,不能同时为多个客户服务
  • 类似于找一个“明星”签字一样,客户需要耐心等待才可以获取到服务
  • 当recv接收数据时,返回值为空,即没有返回数据,那么意味着客户端已经调用了close关闭了;因此服务器通过判断recv接收数据是否为空 来判断客户端是否已经下线

2.如何实现并发的?

from socket import *
from multiprocessing import Pool serSocket = socket(AF_INET, SOCK_STREAM)
serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)
#1表示端口可以充分使用,不会出现already used
localAddr = ('', 7788)
serSocket.bind(localAddr)
serSocket.listen(5) 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():
while True:
print('-----主进程,,等待新客户端的到来------')
newSocket,destAddr = serSocket.accept()
print('-----主进程,,接下来负责数据处理[%s]-----'%str(destAddr)) client = Pool(targetc=dealWithClient,args=(newSocket,destAddr))
client.start() newSocket.close() #新的进程以及有套接字,此时的套接字,不需要了 serSocket.close() if __name__ == "__main__":
main()

3. 多进程服务器:进程占用的资源多

from socket import *
from multiprocessing import *
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 = Process(target=dealWithClient, args=(newSocket,destAddr))
client.start() #因为已经向子进程中copy了一份(引用),并且父进程中这个套接字也没有用处了
#所以关闭
newSocket.close()
finally:
#当为所有的客户端服务完之后再进行关闭,表示不再接收新的客户端的链接
serSocket.close() if __name__ == '__main__':
main()
  • 通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服务
  • 当客户端不是特别多的时候,这种方式还行,如果有几百上千个,就不可取了,因为每次创建进程等过程需要好较大的资源

    

  • 写时copy:进程先调用,不到万不得已,才copy一份

    

4.多线程服务器:线程共用同一份进程资源

#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()
  • 模拟tcp客户端,多线程可以连接

    

5.单进程服务器:非阻塞模式

#将套接字设置为非堵塞
#设置为非堵塞后,如果accept时,恰巧没有客户端connect,那么accept会
#产生一个异常,所以需要try来进行处理
serSocket.setblocking(False)
from socket import *
#1.创建socket
serSocket = socket(AF_INET, SOCK_STREAM) #2. 绑定本地ip以及port
localAddr = ('', 7788)
serSocket.bind(localAddr) #3. 让这个socket 变为非堵塞
serSocket.setblocking(False) #4. 将socket变为监听(被动)套接字
serSocket.listen(100) # 用来保存所有已经连接的客户端的信息
clientAddrList = [] while True: #等待一个新的客户端的到来(即完成3次握手的客户端)
try:
clientSocket,clientAddr = serSocket.accept()
except:
pass
else:
print("一个新的客户端到来:%s"%str(clientAddr))
clientSocket.setblocking(False)
clientAddrList.append((clientSocket,clientAddr)) for clientSocket,clientAddr in clientAddrList:
try:
recvData = clientSocket.recv(1024)
except:
pass
else:
if len(recvData)>0:
print("%s:%s"%(str(clientAddr), recvData))
else:
clientSocket.close()
clientAddrList.remove((clientSocket, clientAddr))
print("%s 已经下线"%str(clientAddr))

    

12 TCP服务器 进程 线程 非阻塞的更多相关文章

  1. 利用Python中SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 版权声明 本文转自:http://blog.csdn.net/cnmilan/article/details/9664823 ...

  2. 【python】网络编程-SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信.首先,先了解下SocketServer模块中可供使用的类:BaseServer:包含服务器的核心功能与混合(mix-in)类 ...

  3. 阻塞IO、非阻塞IO、同步IO、异步IO等

    https://www.cnblogs.com/zingp/p/6863170.html 阅读目录 1 基础知识回顾 2 I/O模式 3 事件驱动编程模型 4 select/poll/epoll的区别 ...

  4. 性能追击:万字长文30+图揭秘8大主流服务器程序线程模型 | Node.js,Apache,Nginx,Netty,Redis,Tomcat,MySQL,Zuul

    本文为<高性能网络编程游记>的第六篇"性能追击:万字长文30+图揭秘8大主流服务器程序线程模型". 最近拍的照片比较少,不知道配什么图好,于是自己画了一个,凑合着用,让 ...

  5. 非阻塞式I/O

    套接字的默认状态是阻塞的.这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待相应的操作完成.可能阻塞的套接字调用可分为以下4类 (1)输入操作,包括read,readv,recv ...

  6. 同步异步,阻塞非阻塞 和nginx的IO模型

    同步与异步 同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication).所谓同步,就是在发出一个*调用*时,在没有得 ...

  7. I/O模型(同步、非同步、阻塞、非阻塞)总结

    I/O:同步(synchronous).异步(asynchronous).阻塞(blocking).非阻塞(nonblocking) 1.I/O内部机制 出于安全考虑,用户程序(用户态)是没办法直接操 ...

  8. (转)同步异步,阻塞非阻塞 和nginx的IO模型

    同步异步,阻塞非阻塞 和nginx的IO模型  原文:https://www.cnblogs.com/wxl-dede/p/5134636.html 同步与异步 同步和异步关注的是消息通信机制 (sy ...

  9. 【python】-- 事件驱动介绍、阻塞IO, 非阻塞IO, 同步IO,异步IO介绍

    事件驱动介绍 一.前言 通常,我们写服务器处理模型的程序时,有以下几种模型: (1)每收到一个请求,创建一个新的进程,来处理该请求: (2)每收到一个请求,创建一个新的线程,来处理该请求: (3)每收 ...

随机推荐

  1. angular2 里父子组件传值的坑

    1.如果传的是基本类型的值,子组件里改变该值,父组件无变化 2.如果传的是对象,子组件里改变对象里的变量,父组件会变化 3.如果传的是函数,this不会继续指向父组件对象了,如果需要this指向父组件 ...

  2. hdu-1492 The number of divisors(约数) about Humble Numbers---因子数公式

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1492 题目大意: 给出一个数,因子只有2 3 5 7,求这个数的因子个数 解题思路: 直接求出指数即 ...

  3. 51nod 1442 士兵的旅行

    拆点,因为只能走一步,那么u->v 后就不能到k了,这样,建图就能保证只走一步: #include <bits/stdc++.h> using namespace std; *; c ...

  4. VMware虚拟机修改BIOS启动项

    vmware默认是硬盘启动,要进bios里面设置成开机的启动顺序,要将光盘设置成第一启动项.但vm的开机画面比笔记本的还要快很多,基本都在1s内的,想进入 bios里面也有难度.. 对于网上说的开vm ...

  5. Struts2 第二讲 -- Struts2的入门

    搭建struts2环境时,我们一般需要做以下几个步骤的工作: 第一步:创建javaweb工程(这个很废话有木有) 第二步:找到开发Struts2应用需要使用到的jar文件.(这个很白痴有没有) 到ht ...

  6. 简析--HashCode

    内容转载自:http://www.cnblogs.com/szlbm/p/5806226.html 哈希表 在了解HashCode之前,我们先来认识一下哈希表; 散列表(Hash table,也叫哈希 ...

  7. Linux_vsftpd服务配置

    首先安装Linux 企业版第一张光盘中的vsftpd-2.0.1-5.i386.rpm#rpm –ivh /media/cdrom/RedHat/RPMS/vsftpd-3.0.1-5.i386.rp ...

  8. v-if和v-show的区别以及callback回调函数的体会

    今天总结一下最近一周碰到的一些问题 一.v-if和v-show的区别 v-show用的是css属性中的display="block/none",元素被隐藏了但是节点还在页面中,但是 ...

  9. js函数只触发一次

    如何让js中的函数只被执行一次?我们有时候会有这种需求,即让一个函数只执行一次,第二次调用不会返回任何有价值的值,也不会报错.下面将通过三个小demo展示使用的方法,当做个人笔记. 1.通过闭包来实现 ...

  10. window/linux下获取文件MD5

    MD5消息摘要算法(英语: MD5 Message-Digest Algorithm), 主要用于确保信息传输过程的一致性校验.   首先介绍两个工具: window: WinMD5Free Linu ...