一、客户端/服务器架构 硬件C/S架构(打印机) 软件C/S架构(web服务) server端要求: 力求一直提供服务 要绑定一个唯一的地址,客户端可以明确的找到 二、基于tcp协议的简单套接字
一、客户端/服务器架构
硬件C/S架构(打印机)软件C/S架构(web服务)server端要求:力求一直提供服务要绑定一个唯一的地址,客户端可以明确的找到二、基于tcp协议的简单套接字
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它时一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Scoket接口后面基于文件类型的套接字家族AF_UNIXAF_INET(基于网络通信)套接字的工作流程socket()模块函数用法importsocketsocket.socket(socket_family,socket_type,protocal=0)socket_family
可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为0。获取tcp/ip套接字
tcpSock =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
获取udp/ip套接字
udpSock =socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
由于socket模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用'from socket import *',我们就把socket模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。例如tcpSock =socket(AF_INET, SOCK_STREAM)服务端套接字函数客户端套接字函数公用用途的套接字函数代码示例"""
tcp服务端
"""
import socket
IP_ADDR = ('127.0.0.1', 8001)
# 创建服务器套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 加入一条socket配置,重用ip和端口
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 把地址绑定到套接字
sock.bind(IP_ADDR)
# 监听链接
sock.listen(5)
while True: # 服务器无限循环
conn, address = sock.accept() # 接受客户端链接
print(address)
while True: # 通信循环
msg = conn.recv(1024) # 对话(接收)
conn.send(msg.upper()) # 对话(发送)
conn.close()
sock.close()
"""
tcp客户端
"""
import socket
IP_ADDR = ('127.0.0.1', 8001)
# 创建服务器套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 尝试连接服务器
sock.connect(IP_ADDR)
while True:
cmd = input('>>>').strip()
sock.send(cmd.encode('utf-8')) # 对话(发送/接收)
msg = sock.recv(1024)
print(msg)
sock.close()
6、关于套接字conn, address = phone.accept()中conn的内容import socket
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.bind(('127.0.0.1', 8080))
phone.listen(5)
while True:
conn, address = phone.accept()
print(conn)
print(address)
while True:
data = conn.recv(1024)
print(data)
conn.send(data.upper())
conn.close()
conn.close()
客户端输出数字后运行结果:
<socket.socket fd=536, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 56964)>
('127.0.0.1', 56964)
b'da'
b'dasdasd'
二、粘包的现象
只有TCP有粘包的现象,UDP永远不会粘包,粘包的问题是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的TCP是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有--成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方UDP是无连接的,面向消息的,提供高效率服务,不会使用块的合并优化算法自制报头解决粘包问题报头(真实数据的描述信息,数字不能编码成bstyp格式三、多线程编程
基于tcp协议的socketserver- 基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环
- socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)
- server类
- request类
- 继承关系
import socketserver
class FTPserver(socketserver.BaseRequestHandler):
def handle(self):
print('dasdas',self)
print(self.request) # self.request = conn
while True: # 通信循环
data = self.request.recv(1024)
print(data)
self.request.send(data.upper())
if __name__ == '__main__':
obj = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), FTPserver)
obj.serve_forever() # 链接循环
分析socketserver源码与通信有关的,BaseRequestHandler,StearmRequsetHandler,DatagramRequestHandler以下列代码为例:ftpserver = socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.server_forever()源码分析总结:基于TCP的socketserver我们自己定义的类中的- self.server即套接字对象
- self.request即一个链接
- self.client_address即客户端地址
基于UDP的socketserver我们自己定义的类中的
面向对象的网络编程服务器端"""
面向对象的网络编程服务器端
"""import socketclassMyServer: address_family = socket.AF_INET# socket_type = socket.SOCK_STREAM
listen_num =5receive_pack_size =1024coding ='utf-8'decoding ='gbk'def__init__(self, ip_address, bind_and_activate=True):self.ip_address = ip_addressself.socket = socket.socket(self.address_family,self.socket_type)ifbind_and_activate:try:self.server_bind()self.server_activate()except:self.server_close()defserver_bind(self):self.socket.bind(self.ip_address)self.ip_address =self.socket.getsockname()defserver_activate(self):self.socket.listen(self.listen_num)defserver_close(self):self.socket.close()defget_request(self):returnself.socket.accept() @staticmethoddefclose_request(request): request.close()defrun(self):whileTrue:self.conn,self.client_address =self.get_request() print('starting...')whileTrue:data =self.conn.recv(self.receive_pack_size)self.conn.send(data)server1 = MyServer(('127.0.0.1',8080))server1.run()