第1章 互联网常见架构:
shell
C/S:客户端和服务端浏览器
常见:wechat/qq缓存
B/S:浏览器和服务器服务器
常见:全部浏览器都是BS架构网络
Socket就是一系列接口,把传输层一下的协议都封装成了简单的接口架构
目的是要编写一个CS架构的软件并发
server端必须具有的特色:ssh
1. 一直对外服务socket
2. 必须绑定一个固定的地址tcp
3. 支持并发
1. 基于文件类型的套接字:AF_UNIX
两个文件同时位于一个机器上,则能够共用一个文件系统来进行通讯
2. 基于网络类型的套接字:AF_INET
先从服务端提及,服务端先初始化socket,而后与端口绑定,对端口进行监听,调用accept阻塞,等待客户端链接,在这时若是有个客户端初始化一个socket,而后链接服务器connect,若是链接成功,这时客户端与服务端的链接就创建了,客户端发送数据请求,服务端接受请求并处理请求,而后把数据发送给客户端,客户端读取数据,最后关闭链接,一次交互结束
服务端套接字函数:
s.bind()绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的链接,(阻塞式)等待链接的到来
客户端套接字函数:
s.connect() 主动初始化TCP服务器链接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数:
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 链接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
面向锁的套接字方法:
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操做的超时时间
s.gettimeout() 获得阻塞套接字操做的超时时间
服务端:
import socket
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(3)
10
print('来自客户端的请求')
print(addr)
data=conn.recv(1024)
print('来自客户端的消息:',data)
conn.send(data.upper())
conn.close()
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
client.send(bytes('nihao',encoding='utf-8'))
data=client.recv(1024)
print('来自服务端的数据:',data)
client.close()
服务端:
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(3)
conn,addr=server.accept()
print(addr)
while True:
data=conn.recv(1024)
iflen(data) == 0 : break
print('来自客户端的消息:',data)
conn.send(data.upper())
conn.close()
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ').strip()
iflen(msg) == 0 :continue
client.send(bytes(msg,encoding='utf-8'))
data=client.recv(1024)
print(data)
client.close()
import socket
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr=server.accept()
while True:
try:
data=conn.recv(1024)
iflen(data) == 0:break
print(data)
conn.send(data.upper())
exceptConnectionRefusedError as e:
break
conn.close()
服务端:
import socket
import subprocess
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr=server.accept()
while True:
try:
data=conn.recv(1024)
iflen(data) == 0:break
obj=subprocess.Popen(data.decode('utf-8'),
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
conn.send(stdout+stderr)
exceptConnectionRefusedError as e:
break
conn.close()
server.close()
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ').strip()
iflen(msg) == 0 :continue
client.send(bytes(msg,encoding='utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
client.close()
要知道:只有tcp有粘包现象,UDP则永远没有
就是接受方不知道消息之间的界限,不知道一次性提取多少字节所形成的
问题的根源在于,接受端不知大发送端将要传送的字节流的长度,因此解决粘包的方法就是围绕,如何让发送端在发送数据前把本身将要发送的字节流总大小让接收端知晓,而后接收端来一个死循环接受全部数据便可
解决粘包问题服务端:
import socket
import struct
import subprocess
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr=server.accept()
while True:
try:
data=conn.recv(1024)
iflen(data) == 0:break
obj=subprocess.Popen(data.decode('utf-8'),
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
#发送固定长度的报头
total_size=len(stdout) + len(stderr)
conn.send(struct.pack('i',total_size))
#真实数据
conn.send(stdout+stderr)
exceptConnectionRefusedError as e:
break
conn.close()
server.close()
客户端:
import socket
import struct
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ').strip()
iflen(msg) == 0 :continue
client.send(bytes(msg,encoding='utf-8'))
#接受数据长度
header=client.recv(4)
total_size=struct.unpack('i',header)[0]
recv_size=0
res=b''
whilerecv_size < total_size:
recv_data=client.recv(1024)
res+=recv_data
recv_size+=len(recv_data)
print(res.decode('utf-8'))
client.close()
服务端:
import socket
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))
while True:
data,client_addr=server.recvfrom(1024)
print('===>',data,client_addr)
server.sendto(data.upper(),client_addr)
server.close()
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg=input('>>: ').strip()
client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
data,server_addr=client.recvfrom(1024)
print(data)
client.close()