目录:

  1、Socket语法及相关

  2、SocketServer实现多并发

Socket语法及相关

socket概念

socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。 我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 。

建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务端被动等待并接收请求,客户端主动发起请求, 连接建立之后,双方可以互发数据。

网络套接字是跨计算机网络的连接的端点。 今天,计算机之间的大多数通信都基于互联网协议; 因此大多数网络套接字都是Internet套接字。 更准确地说,套接字是一个句柄(抽象引用),

本地程序可以将其传递给网络应用程序编程接口(API)以使用该连接,例如“在此套接字上发送此数据”。 套接字在内部通常只是整数,它标识要使用的连接。

例如,发送“Hello,world!” 通过TCP到地址为1.2.3.4的主机的端口80,可以获得一个套接字,将其连接到远程主机,发送字符串,然后关闭套接字:

Socket socket = getSocket(type = "TCP")
connect(socket, address = "1.2.3.4", port = "")
send(socket, "Hello, world!")
close(socket)

套接字API是一种应用程序编程接口(API),通常由操作系统提供,允许应用程序控制和使用网络套接字。 Internet套接字API通常基于Berkeley套接字标准。在Berkeley套接字标准中,套接字是文件描述符(文件句柄)的一种形式,

由于Unix哲学“一切都是文件”,以及套接字和文件之间的类比:你可以读,写,打开和关闭都。在实践中,差异意味着类比是紧张的,而一个在套接字上使用不同的接口(发送和接收)。

在进程间通信中,每个端口通常都有自己的套接字,但这些套接字可能使用不同的API:它们由网络协议抽象。

套接字地址是IP地址和端口号的组合,很像电话连接的一端是电话号码和特定分机的组合。套接字不需要有地址(例如仅用于发送数据),但如果程序将套接字绑定到地址,则套接字可用于接收发送到该地址的数据。

基于此地址,Internet套接字将传入的数据包传递到适当的应用程序进程或线程。

Socket Families(地址簇)

socket.AF_UNIX unix本机进程间通信 

socket.AF_INET IPV4 

socket.AF_INET6  IPV6

这些常量表示用于socket()的第一个参数的地址(和协议)系列。 如果未定义AF_UNIX常量,则不支持此协议。 根据系统的不同,可能会有更多常量可用

Socket Types

socket.SOCK_STREAM  #for tcp

socket.SOCK_DGRAM   #for udp 

socket.SOCK_RAW     #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

socket.SOCK_RDM  #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。

这些常量表示套接字类型,用于socket()的第二个参数。 根据系统的不同,可能会有更多常量可用。 (只有SOCK_STREAM和SOCK_DGRAM似乎通常很有用。)

Socket 方法

socket.socket(family=AF_INETtype=SOCK_STREAMproto=0fileno=None)

使用给定的地址系列,套接字类型和协议号创建一个新套接字。 地址族应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 套接字类型应该是SOCK_STREAM(默认值),

SOCK_DGRAM,SOCK_RAW或者其他SOCK_常量之一。 协议号通常为零并且可以省略,或者在地址族是AF_CAN的情况下,协议应该是CAN_RAW或CAN_BCM之一。

如果指定了fileno,则忽略其他参数,从而返回具有指定文件描述符的套接字。 与socket.fromfd()不同,fileno将返回相同的套接字而不是重复。 这可能有助于使用socket.close()关闭分离的套接字

socket.socketpair([family[, type[, proto]]])

使用给定的地址系列,套接字类型和协议编号构建一对连接的套接字对象。 地址族,套接字类型和协议号与上面的socket()函数相同。 如果在平台上定义,则默认系列为AF_UNIX; 否则,默认为AF_INET。

socket.create_connection(address[, timeout[, source_address]])

连接到侦听Internet地址(2元组(主机,端口))的TCP服务,并返回套接字对象。 这是一个比socket.connect()更高级的函数:如果host是非数字主机名,它将尝试为AF_INET和AF_INET6解析它,

然后尝试依次连接到所有可能的地址,直到连接成功。 这样可以轻松编写与IPv4和IPv6兼容的客户端。

传递可选的timeout参数将在尝试连接之前设置套接字实例上的超时。 如果未提供超时,则使用getdefaulttimeout()返回的全局默认超时设置。

如果提供,则source_address必须是要连接的套接字的2元组(主机,端口)作为其源地址才能连接。 如果主机或端口分别为'或0,则将使用OS默认行为。

socket.getaddrinfo(hostportfamily=0type=0proto=0flags=0) #获取要连接的对端主机地址

sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)

参数一:地址簇

  socket.AF_INET IPv4(默认)
  socket.AF_INET6 IPv6

  socket.AF_UNIX 只能够用于单一的Unix系统进程间通信

参数二:类型

  socket.SOCK_STREAM  流式socket , for TCP (默认)
  socket.SOCK_DGRAM   数据报式socket , for UDP

  socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  socket.SOCK_SEQPACKET 可靠的连续数据包服务

参数三:协议

  0  (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

sk.bind(address)

  s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)

  开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。

backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
      这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)

  是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()

  接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

  接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)

  连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

  同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close()

  关闭套接字

sk.recv(bufsize[,flag])

  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag])

  将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])

  将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

  将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout)

  设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername()

  返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()

  返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()

  套接字的文件描述符

socket.sendfile(fileoffset=0count=None)

socket实例1

#先启动服务端,再启动客户端

#服务器端
import socket
server = socket.socket()#声明socket类型,同时生成socket连接对象 server.bind(('localhost',6969))#绑定要监听的端口 server.listen()#开始监听
print("我要等电话了:") conn,addr = server.accept()#等电话打进来
#conn是客户端连接过来而在服务器端为其生成的一个连接实例
print(conn,addr) print("电话来了") data = conn.recv(1024)
print("recv:",data.decode()) conn.send(data.upper()) server.close()
#客户端

import socket

client = socket.socket()#声明socket类型,同时生成socket连接对象

client.connect(('localhost',6969))

#client.send(b'hello python!')#b只能发送Ascii对应的字符
client.send('鲁班大师智障250,oh,yeah!'.encode('utf-8'))
data = client.recv(1024)#接收返回值
print("recv:",data.decode()) client.close()#关闭客户端

运行结果:

#客户端
recv: 鲁班大师智障250,OH,YEAH!
#服务器端 我要等电话了:
<socket.socket fd=584, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 51079)> ('127.0.0.1', 51079)
电话来了
recv: 鲁班大师智障250,oh,yeah!

socket实例2

#Author:Yun
'''
缓冲区:
1、当缓冲区满了后自动发
2、超时后触发发送 '''
import socket, os,time server = socket.socket()
server.bind(('localhost', 998))
server.listen()
while True:
print("等待新的客户端:")
conn,addr = server.accept() print("New conn:",addr)
try:
while True:
data = conn.recv(1024)
print("执行指令:",data)
res_cmd = os.popen(data.decode()).read()#执行结果是字符串,接受结果也是字符串
if len(res_cmd) == 0:
res_cmd = "cmd has no output!"
conn.send(str(len(res_cmd.encode())).encode('utf-8'))#返回要出输给客户端的文件大小
client_ack = conn.recv(1024)#wait client to confirm(确认)
conn.send(res_cmd.encode('utf-8'))#给客户端传输数据
print("send done!")
except ConnectionResetError as e:
print("客户端已关闭:",e)
server.close()

server

#Author:Yun
'''
输入:dir 服务器会返回当前目录下的文件
ipconfig 服务器会返回计算机ip的配置信息
''' import socket client = socket.socket() client.connect(('localhost',998)) while True:
cmd = input('>>:').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8'))
res_cmd_size = client.recv(1024)#获取服务器返回数据的总大小
print("命令结果大小:",int(res_cmd_size.decode()))
client.send("准备好接受了,可以发送了!".encode('utf-8'))
recived_size = 0
recived_data = b''
while recived_size < int(res_cmd_size.decode()):
cmd_res = client.recv(1024)
recived_size += len(cmd_res)#每次接收到的有可能小于1024,必须要用len()判断
recived_data += cmd_res else:
print("cmd res recive done...",recived_size)
print(recived_data.decode())
client.close()

client

socket实例3

2、SocketServer实现多并发

SocketServer

socketserver模块简化了编写网络服务器的任务。

有四种基本的具体服务器类:

class socketserver.TCPServer(server_addressRequestHandlerClassbind_and_activate=True)
它使用Internet TCP协议,该协议在客户端和服务器之间提供连续的数据流。 如果bind_and_activate为true,则构造函数会自动尝试调用server_bind()和server_activate()。 其他参数将传递给BaseServer基类。
class socketserver.UDPServer(server_addressRequestHandlerClassbind_and_activate=True)
这使用数据报,这些数据报是可能无序到达或在传输过程中丢失的离散信息包。 参数与TCPServer相同。
class socketserver.UnixStreamServer(server_addressRequestHandlerClassbind_and_activate=True)
class socketserver.UnixDatagramServer(server_addressRequestHandlerClass,bind_and_activate=True)
这些不经常使用的类类似于TCP和UDP类,但使用Unix域套接字; 它们不适用于非Unix平台。 参数与TCPServer相同。

这四个类同步处理请求; 必须在下一个请求开始之前完成每个请求。 如果每个请求需要很长时间才能完成,这是不合适的,因为它需要大量计算,或者因为它返回了客户端处理速度慢的大量数据。

解决方案是创建一个单独的进程或线程来处理每个请求; ForkingMixIn和ThreadingMixIn混合类可用于支持异步行为。

继承图中有五个类,其中四个代表四种类型的同步服务器:

请注意,UnixDatagramServer派生自UDPServer,而不是来自UnixStreamServer - IP和Unix流服务器之间的唯一区别是地址族,这在两个Unix服务器类中都是重复的。

class socketserver.ForkingMixIn
class socketserver.ThreadingMixIn

可以使用这些混合类创建每种类型服务器的分叉和线程版本。 例如,ThreadingUDPServer创建如下:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
pass
class socketserver.ForkingTCPServer
class socketserver.ForkingUDPServer
class socketserver.ThreadingTCPServer
class socketserver.ThreadingUDPServer

这些类是使用混合类预定义的。

Request Handler Objects
class socketserver.BaseRequestHandler

这是所有请求处理程序对象的超类。 它定义了接口,如下所示。 具体的请求处理程序子类必须定义新的handle()方法,并且可以覆盖任何其他方法。 为每个请求创建子类的新实例。

setup()
在handle()方法之前调用以执行所需的任何初始化操作。 默认实现什么都不做。
handle()
此功能必须完成服务请求所需的所有工作。 默认实现什么都不做。 有几个实例属性可用; 请求以self.request的形式提供; 客户端地址为self.client_address; 并且服务器实例为self.server,以防它需要访问每服务器信息。

self.request的类型对于数据报或流服务是不同的。 对于流服务,self.request是一个套接字对象; 对于数据报服务,self.request是一对字符串和套接字。

finish()
在handle()方法之后调用以执行所需的任何清理操作。 默认实现什么都不做。 如果setup()引发异常,则不会调用此函数。

socketserver.TCPServer Example

server side

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
"""
我们服务器的请求处理程序类。
 
     每次连接到服务器时都会实例化一次,并且必须
     覆盖handle()方法以实现与的通信
     客户。
""" def handle(self):
# self.request是连接到客户端的TCP套接字
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# 只是发回相同的数据,但大写
self.request.sendall(self.data.upper()) if __name__ == "__main__":
HOST, PORT = "localhost", 9999 # 创建服务器,绑定到端口9999上的localhost
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) # 激活服务器; 这会继续运行直到你
# 使用Ctrl-C中断程序
server.serve_forever()

client side 

import socket
import sys HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:]) # Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(bytes(data + "\n", "utf-8")) # Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
finally:
sock.close() print("Sent: {}".format(data))
print("Received: {}".format(received))

上面这个例子你会发现,依然不能实现多并发,只需在server端做一下更改就可以了

把服务器端的

server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
改成
 
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
 
socketserver实例1
简单版的文件的上传下载,注意(需将要上传的文件与客户端程序在同一路径,需将要下载的文件与服务端程序在同一路径)
#Author:Yun
import socketserver
import json,os,sys,time
class MyTCPHandler(socketserver.BaseRequestHandler): def put(self,*args):
'''
接收客户端文件 :return:
'''
cmd_dic = args[0]
print('cmd_dic',cmd_dic)
filename = cmd_dic["filename"] file_size = cmd_dic["size"] if os.path.isfile(filename):
f = open(filename + '.new','wb') else:
f = open(filename,'wb') self.request.send(b'200 ok') received_size = 0
nn = []
h =0
while received_size < file_size:
self.data = self.request.recv(1024)
f.write(self.data)
received_size += len(self.data)
#进度显示
n = int(received_size / file_size * 100)
if h == n:continue
print(n,'%')
h = n else:
print("\033[33;1mfile [%s] has uploaded....\033[;0m"%filename) def get(self,*args):
print(args[0])
#获取客户端要下载的文件名
file_name =args[0]['filename']
if os.path.isfile(file_name): file_size = os.stat(file_name).st_size
self.request.send(str(file_size).encode('utf-8'))
#防止粘包
self.request.recv(1024)#等待客户端确认
while True: f = open(file_name,'rb')
for line in f:
self.request.send(line)
else:
f.close()
break
print('file [%s] send done!'%file_name)
def handle(self):
while True:
try:
print('等待新命令:')
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
cmd_dict = json.loads(self.data.decode())
action = cmd_dict["action"]
if hasattr(self,action):
func = getattr(self,action)
func(cmd_dict)
except ConnectionResetError as e:
print("Error:",e)
break if __name__ == '__main__':
HOST,PORT = 'localhost',9898
sever = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
sever.serve_forever()

server

#Author:Yun
import socket
import os,json class FtpClient(object):
def __init__(self):
self.client = socket.socket() def help(self):
msg = '''
ls pwd cd ../.. get filename put filename '''
def connect(self,ip,port):
self.client.connect((ip,port)) def interactive(self): while True:
cmd = input((">>>:")).strip()
if len(cmd) == 0:continue cmd_str = cmd.split()[0]
#print(cmd_str)
if hasattr(self,'cmd_%s'%cmd_str):
func = getattr(self,'cmd_%s'%cmd_str) func(cmd)
else:
self.help()
def cmd_put(self,*args):
#print(args[0])
cmd_split = args[0].split()#返回分割后的字符串列表,默认以空格为分割符
print('cmd_split:',cmd_split)
if len(cmd_split) >1:#如果长度大于1怎说明命令后面还有文件名
filename = cmd_split[1]
#print(filename)
if os.path.isfile(filename):
file_size = os.stat(filename).st_size
msg_dic = { "action":'put',
"filename":filename,
"size":file_size,
"overridden":True
}
#print(msg_dic)
self.client.send(json.dumps(msg_dic).encode('utf-8'))
#防止粘包
server_response = self.client.recv(1024)
f = open(filename,'rb')
while True:
for line in f:
self.client.send(line)
else:
print("\033[32;1mfile update success!\033[;0m")
f.close()
break
else:
print(filename,"\033[31;1mis not exist!\033[;0m") def cmd_get(self,*args):
print(args[0])
cmd_split = args[0].split()#返回分割后的字符串列表,默认以空格为分割符
#获取文件名
if len(cmd_split) > 1:#如果长度大于1,说明包含文件名
filename = cmd_split[1]
msg_dic = { "action": 'get',
"filename": filename,
"overridden": True
}
print(msg_dic)
# 向服务器发出请求
self.client.send(json.dumps(msg_dic).encode('utf-8'))
# 获取文件大小
server_response = self.client.recv(1024)
file_total_size = int(server_response.decode())
print('file_total_size:', file_total_size)
# 防止粘包
self.client.send(b'Ready,you can send it. ')
f = open(filename + '.in_client', 'wb')
received_size = 0
h = 0
while received_size < file_total_size:
if (file_total_size - received_size) > 1024:
size = 1024
else:
size = file_total_size - received_size
data = self.client.recv(size)
f.write(data)
received_size += len(data)
n = int(received_size / file_total_size * 100)
if h == n: continue
print(n, '%')
h = n
else:
print('received_size:', received_size)
f.close()
print("your file download success!") ftp = FtpClient()
ftp.connect('localhost',9898)
ftp.interactive()

client

Day8-Python3基础-Socket网络编程的更多相关文章

  1. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  2. Python之旅Day8 socket网络编程

    socket网络编程 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可.soc ...

  3. Java Web 基础(一) 基于TCP的Socket网络编程

    一.Socket简单介绍 Socket通信作为Java网络通讯的基础内容,集中了异常.I/O流模式等众多知识点.学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解. 1 ...

  4. Socket网络编程-基础篇

    Socket网络编程 网络通讯三要素: IP地址[主机名] 网络中设备的标识 本地回环地址:127.0.0.1 主机名:localhost 端口号 用于标识进程的逻辑地址 有效端口:0~65535 其 ...

  5. 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 2

    BSD Socket网络编程API 创建socket对象 int socket (int __domain, int __type, int __protocol) :成功返回socket文件描述符, ...

  6. Python面向对象进阶和socket网络编程-day08

    写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...

  7. Python面向对象进阶和socket网络编程

    写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self ...

  8. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  9. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

随机推荐

  1. SpringBoot如何优雅的使用RocketMQ

    目录 SpringBoot如何优雅的使用RocketMQ SpringBoot如何优雅的使用RocketMQ MQ,是一种跨进程的通信机制,用于上下游传递消息.在传统的互联网架构中通常使用MQ来对上下 ...

  2. 想突破学习瓶颈,为什么要认真的学一下Dubbo?

    今天有学生在问,在学习dubbo的时候遇到瓶颈了怎么办,一些东西就感觉就在那里,但是,就是碰不到,摸不着,陷入了迷茫,今天在这里,就跟大家讲一下怎么突破这个瓶颈 先自我介绍一下哈,我是鲁班学院的周瑜老 ...

  3. java面试-泛型

    1.什么是泛型?泛型有什么作用?   泛型就是参数化类型,也就是所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法.   在泛型出现之前, ...

  4. spring定时器时间设置规则

    单纯针对时间的设置规则org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间,只需要设置其cronExpressio ...

  5. python 连接 SQL Server 数据库

    #!/usr/bin/python # -*- coding:utf-8 -*- import pymssql import pyodbc host = '127.0.0.1:1433' user = ...

  6. 【他山之石】jenkins忘记初始化密码解决办法

    没有太好的方式,网上有的是这样子的,找到 /var/lib/jenkins/users/username/config.xml, 修改为一个已知的 hash 值 #jbcrypt:$2a$10$Dda ...

  7. SpringBoot简介与快速入门

    一.SpringBoot简介 1.1 原有Spring优缺点分析 1.1.1 Spring的优点分析 Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE ...

  8. Python 元类的基本介绍及使用

    一.什么是元类 二.如何使用元类 (一)不依赖class关键字创建一个自定义类 (二)自定义元类控制类的产生 (三)自定义元类控制类的调用 一.什么是元类 在python中,一切皆对象,而对象都是由类 ...

  9. DRF 08

    目录 三大认证 流程 认证组件 权限组件 频率组件 自定义token的签发 三大认证 流程 由于DRF中, 所有的视图类都要直接和间接继承APIView类, 也只有APIView类中才有dispatc ...

  10. 啊哈!C语言课后参考答案上

    最近看到一本好评量很高的的C语言入门书,课本真的很好,入门的话.专业性没有那么强,但入门足够了!!好评!看着看着就想把这本书的题课后习题都写出来,最后就有了这个小结.可能有的不是最好,不那么专业,但主 ...