一、多线程版
server.py
import socket
from threading import Thread
import re
import time
"""
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
family:choose one from [
AF_UNIX —————————— unix本机之间进行通信
AF_INET —————————— 使用IPv4
F_INET6 —————————— 使用IPv6
type:
SOCK_STREAM # TCP套接字类型
SOCK_DGRAM # UDP套接字类型
SOCK_RAW #原始套接字类型,这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧
SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
setsockopt(level,optname,value)
level:通常情况下是SOL_SOCKET,意思是正在使用的socket选项。
optname:
SO_BINDTODEVICE:可以使socket只在某个特殊的网络接口(网卡)有效。也许不能是移动便携设备
SO_BROADCAST:允许广播地址发送和接收信息包。只对UDP有效。如何发送和接收广播信息包
SO_DONTROUTE:禁止通过路由器和网关往外发送信息包。这主要是为了安全而用在以太网上UDP通信的一种方法。不管目的地址使用什么IP地址,都可以防止数据离开本地网络
SO_KEEPALIVE:可以使TCP通信的信息包保持连续性。这些信息包可以在没有信息传输的时候,使通信的双方确定连接是保持的
SO_OOBINLINE:可以把收到的不正常数据看成是正常的数据,也就是说会通过一个标准的对recv()的调用来接收这些数据
SO_REUSEADDR:当socket关闭后,本地端用于该socket的端口号立刻就可以被重用。通常来说,只有经过系统定义一段时间后,才能被重用。
"""
def funcThread(sock,addr):
print("a new link from ip:%s" % addr[0])
sock.send(b"welcome")
while(True):
data=sock.recv(1024)
print(data,end=" ")
time.sleep(1)
print(not data)
if(not data):
break
sock.send(("hello,%s" % data.decode("utf-8")).encode("utf-8"))
sock.close()
#创建tcp套接字,
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(("127.0.0.1",8000))
s.listen(10)
while(True):
sock,addr=s.accept()
print(addr)
t=Thread(target=funcThread,args=(sock,addr))
t.start()
client.py
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
print(s.recv(1024).decode("utf-8"))
info=["josh","bob","silly","jane"]
for data in info:
s.send(data.encode("utf-8"))
print(s.recv(1024))
s.send("".encode("utf-8"))
s.close()
二、单进程非堵塞
服务器:
import socket
from threading import Thread
import re
import time
#创建tcp套接字,
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#设置socket为非堵塞
s.setblocking(False)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(("127.0.0.1",8000))
s.listen(10)
socket_list=[]
while(True):
try:
client_sock,addr=s.accept()
client_sock.setblocking(False)
#将接入的客户端也设置为非堵塞
except Exception as e:
pass
else:
# print(addr)
print("a new socket(%s,%s) is coming" % addr)
socket_list.append((client_sock,addr))
for sock,addr in socket_list:
try:
data=sock.recv(1024).decode('utf-8')
except Exception as e:
pass
else:
if(data==""):
print("(%s)has gone" % str(addr))
sock.close()
socket_list.remove((sock,addr))
else:
print("(%s)" % (data,))
partern=re.compile(r'\d')
res=partern.findall(data)
sock.send((res[0]+"你好,我已收到你的第"+res[1]+"次发送的数据").encode("utf-8"))
客户端
import socket
from threading import Thread
def fun1(n):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
for i in range(n):
try:
data="我是线程:(%s),这是我第(%s)次发送数据。"%(n,i)
s.send(data.encode("utf-8"))
print(s.recv(1024).decode('utf-8'))
except Exception as e:
pass
s.send("".encode("utf-8"))
s.close()
for i in range(10):
t=Thread(target=fun1,args=(i,))
t.start()