python socket多线程多进程--步步改进

初始代码:
服务端:
from socket import socket,AF_INET,SOCK_STREAM

tcpserversocket = socket(AF_INET,SOCK_STREAM)
address = (‘10.89.11.104’,9999)
tcpserversocket.bind(address)
tcpserversocket.listen(5)
while True:
newsocket,clientaddr = tcpserversocket.accept()
while True:
recvdata = newsocket.recv(1024)
if len(recvdata)>0:
print(‘recv’,recvdata)
else:
break
senddata = raw_input(“send:”)
newsocket.send(bytes(senddata.encode(‘utf-8’)))
newsocket.close()
tcpserversocket.close()

客户端:
from socket import socket,AF_INET,SOCK_STREAM

tcpclientsocket = socket(AF_INET,SOCK_STREAM)
serveraddress = (‘10.89.11.104’,9999)
tcpclientsocket.connect(serveraddress)
while True:
senddata = input(“send:”)
if senddata == ‘bye’:
break
if len(senddata)>0:
tcpclientsocket.send(bytes(senddata.encode(‘utf-8’)))
else:
break
recvdata = tcpclientsocket.recv(1024)
print(‘recv:’,recvdata)
tcpclientsocket.close()
初始代码的问题:
单线程,客服端和服务端都只能等收到对端的数据才能继续输入

改进1:多线程,服务端和客户端分别用2个线程单独做输入操作和接收操作,不用等待对端的输出。
服务端:
from socket import socket,AF_INET,SOCK_STREAM
import threading
import sys
class myThread1(threading.Thread):
def _init_(self,skt):
threading.Thread._init_(self)
self.skt = skt
def run(self):
senddata = raw_input(“send:”)
if len(senddata)>0:
self.skt.send(bytes(senddata.encode(‘utf-8’)))

class myThread2(threading.Thread):
def _init_(self,skt):
threading.Thread._init_(self)
self.skt = skt
def run(self):
recvdata = self.skt.recv(1024)
if recvdata != None:
print(‘recv:’,recvdata)

tcpserversocket = socket(AF_INET,SOCK_STREAM)
address = (‘10.89.11.104’,9999)
tcpserversocket.bind(address)
tcpserversocket.listen(5)
while True:
newsocket,clientaddr = tcpserversocket.accept()
while True:
thread2 = myThread2(newsocket)
thread1 = myThread1(newsocket)
thread2.start()
thread1.start()
newsocket.close()
tcpserversocket.close()

客户端:
#!/opt/ATC/Python-2.7/bin/python
from socket import socket,AF_INET,SOCK_STREAM
import threading
import sys
class myThread1(threading.Thread):
def _init_(self,skt):
threading.Thread._init_(self)
self.skt = skt
def run(self):
senddata = raw_input(“send:”)
if senddata == ‘bye’:
sys.exit(0)
if len(senddata)>0:
self.skt.send(bytes(senddata.encode(‘utf-8’)))

class myThread2(threading.Thread):
def _init_(self,skt):
threading.Thread._init_(self)
self.skt = skt
def run(self):
recvdata = self.skt.recv(1024)
if recvdata != None:
print(‘recv:’,recvdata)

tcpclientsocket = socket(AF_INET,SOCK_STREAM)
serveraddress = (‘10.89.11.104’,9999)
tcpclientsocket.connect(serveraddress)

while True:
thread1 = myThread1(tcpclientsocket)
thread2 = myThread2(tcpclientsocket)
thread1.start()
thread2.start()

tcpclientsocket.close()
改进1后代码的问题:
(1)线程启用过多错误thread.error: can’t start new thread,可抵达最大值锁后等待释放可以解决
(2)多线程用sys.exit()不能退出,需要用os._exit(0)强制退出;原因是sys.exit()是引发一个SystemExit异常,因为是在子线程引出异常的,所以它是子线程退出,主线程还是正常运行
解决两个问题的代码:
客户端:
from socket import socket,AF_INET,SOCK_STREAM
import threading
import os
class myThread1(threading.Thread):
tlist = []
maxthreads = 100
evnt = threading.Event()
lck = threading.Lock()
def /init(self,skt):
threading.Thread./init(self)
self.skt = skt
def run(self):
senddata = raw_input(“send:”)
if senddata == ‘bye’:
os._exit(0)
if len(senddata)>0:
self.skt.send(bytes(senddata.encode(‘utf-8’)))
myThread1.lck.acquire()
myThread1.tlist.remove(self)
if len(myThread1.tlist)==myThread1.maxthreads-1:
myThread1.evnt.set()
myThread1.evnt.clear()
myThread1.lck.release()
def newthread(skt):
myThread1.lck.acquire()#LOCK
sc=myThread1(skt)
myThread1.tlist.append(sc)
myThread1.lck.release()#UNLOCK
sc.start()
newthread=staticmethod(newthread)

class myThread2(threading.Thread):
tlist = []
maxthreads = 100
evnt = threading.Event()
lck = threading.Lock()
def /init(self,skt):
threading.Thread./init(self)
self.skt = skt
def run(self):
recvdata = self.skt.recv(1024)
if recvdata != None:
print(‘recv:’,recvdata)
myThread2.lck.acquire()
myThread2.tlist.remove(self)
if len(myThread2.tlist)==myThread2.maxthreads-1:
myThread2.evnt.set()
myThread2.evnt.clear()
myThread2.lck.release()
def newthread(skt):
myThread2.lck.acquire()#LOCK
sc=myThread2(skt)
myThread2.tlist.append(sc)
myThread2.lck.release()#UNLOCK
sc.start()
newthread=staticmethod(newthread)

tcpclientsocket = socket(AF_INET,SOCK_STREAM)
serveraddress = (‘10.89.11.104’,9999)
tcpclientsocket.connect(serveraddress)

while True:
myThread1.lck.acquire()
myThread2.lck.acquire()
if len(myThread1.tlist)>=myThread1.maxthreads:
myThread1.lck.release()
myThread1.evnt.wait()
else:
myThread1.lck.release()
myThread1.newthread(tcpclientsocket)
if len(myThread2.tlist)>=myThread2.maxthreads:
myThread2.lck.release()
myThread2.evnt.wait()
else:
myThread2.lck.release()
myThread2.newthread(tcpclientsocket)

tcpclientsocket.close()
服务器端用抵达最大值锁后等待释放会导致问题:释放没有锁的锁
Ctrl+c是强制中断程序的执行,,进程已经终止
Ctrl+z是将任务中止(暂停的意思),此时此任务并没有结束,仍然在进程中他只是维持挂起的状态,
不能用ctrl+c,可以用ctrl+z,查看是进程还在,重新启用服务器会报错:socket.error: [Errno 98] Address already in use用kill pid不能杀死进程需要用kill -9 pid强制杀死进程。

改进2:多个客户端同服务器通信,多进程或多线程;多个客户端时服务器只适合监听,不适合输入数据进行反馈,因为输入数据要针对每一个不同的客户端,目前阶段反馈的只是客户端输入的数据;后面技术提高可以根据不同的客户端的问题做一个智能回应(子进程是不能有input的)
多进程:当前进程是主进程(写在外面的是主进程,写在里面的都是子进程)即负责监听每个客户端并给与连接,子进程则是做target功能即每个客户端连接后接收数据并反馈; process.join() 是阻塞模式,直到process这个子进程执行完毕之后再继续执行后面的子进程,注释掉这一行则多个子进程可以并发操作
服务器端代码:
from socket import socket,AF_INET,SOCK_STREAM
from multiprocessing import Process

def get_client_message(csocket,cinfo):
while True:
recv_data = csocket.recv(1024)
if len(recv_data) == 0:
break
print “info from:”,cinfo,recv_data.decode(“utf-8”)
print cinfo,“disconnect”
csocket.close()

tcpserversocket = socket(AF_INET,SOCK_STREAM)
address = (‘10.89.11.104’,9999)
tcpserversocket.bind(address)
tcpserversocket.listen(5)
while True:
newsocket,clientaddr = tcpserversocket.accept()
process = Process(target=get_client_message,args=(newsocket,clientaddr))
process.start()
process.join() # 阻塞,直到process这个子进程执行完毕之后再继续执行
tcpserversocket.close()

多线程:和多进程类似,当前线程是主线程(写在外面的是主线程,写在里面的都是子线程)即负责监听每个客户端并给与连接,子线程则是做target功能即每个客户端连接后接收数据并反馈。

服务器代码:

from time import ctime
import threading
import sys

tcpserversocket = socket(AF_INET,SOCK_STREAM)
address = (‘10.89.11.104’,9999)
tcpserversocket.bind(address)
tcpserversocket.listen(5)
socks = []

def handle(s,cinfo):
while True:
data = s.recv(1024)
if data:
s.send(’[%s],%s’%(ctime(),data))
else:
break
print(cinfo,“dicconnect”)
s.close()
print threading.current_thread().name
print"waitting for connecting…"
while True:
csock,addr=tcpserversocket.accept()
t = threading.Thread(target=handle,args=(csock,addr))
t.start()
print’connected from:’,addr
tcpserversocket.close()

总结:可以用python自带的Process类或Thread类创建对象并使用其中方法,也可以自己写类继承Process类或Thread类后重定义用到的方法。
https://www.cnblogs.com/xiaozengzeng/p/10723954.html
即两种方法:
1、给构造函数传递回调对象
mthread=threading.Thread(target=xxxx,args=(xxxx))
mthread.start()
2、在子类中重写run() 方法(start会调用run方法),在子类中只有_init_()和run()方法被重写

导入相关模块后才可以查看下面的函数用:
Process类和Thread类有一些相似的函数功能,比如start(),join(),run()

在这里插入图片描述在这里插入图片描述

from threading import Thread
help(Thread.start)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值