Num01-->TCP通信模型

这里写图片描述

Test01-->TCP客户端案例

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

from socket import *

def main():

# 1.创建socket

client_socket = socket(AF_INET, SOCK_STREAM)

# 2.指定服务器的地址和端口号

server_addr = ('192.168.105.125',8080)

client_socket.connect(server_addr)

print('connect %s success' % str(server_addr))

while True:

# 3.给用户提示,让用户输入要检索的资料

send_data = input('>>')

# 退出

if send_data == 'quit':

break

# 向服务器请求数据

client_socket.send(send_data.encode())

client_socket.close()

if __name__ == "__main__":

main()

Test02-->TCP服务器端案例

TCP服务器端创建流程如下:

1,socket创建一个套接字

2,bind绑定ip和port

3,listen使套接字变为可以被动链接

4,accept等待客户端的链接

5,recv/send接收/发送数据

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

from socket import *

import time

def main():

# 1.创建socket,stream流式套接字,对应tcp

listen_socket = socket(AF_INET, SOCK_STREAM)

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 2.绑定端口号

my_addr = ('192.168.105.125', 8080)

#shift + insert

listen_socket.bind(my_addr)

# 3.接听状态

#listen中的black表示已经建立链接和半链接的总数

#如果当前已建立链接数和半链接数以达到设定值,那么新客户端就不会connect成功,而是等待服务器。直到有链接退出。

listen_socket.listen(4)

print('listening...')

# 4.等待客户端来请求服务器

while True:

# 接受连接请求,创建新的连接套接字,用于客户端连通信

connect_socket, client_addr = listen_socket.accept()

# accept默认会引起阻塞

# 新创建连接用的socket, 客户端的地址

# print(connect_socket)

# print(client_addr)

while True:

# tcp recv() 只会返回接收到的数据

# 1024表示接受的数据长度

recv_data = connect_socket.recv(1024)

if len(recv_data) == 0:

#发送方关闭tcp的连接,recv()不会阻塞,而是直接返回''

print('client %s close' % str(client_addr))

time.sleep(5)

break

print('recv: %s' % recv_data.decode('gbk'))

# 用完之后,关闭新创建的那个connect_socket

connect_socket.close()

if __name__ == "__main__":

main()

Num02-->TCP协议三次握手

这里写图片描述

Num03-->TCP协议四次挥手

这里写图片描述

Num04-->TCP协议十种状态

这里写图片描述

当一端收到一个FIN,内核让read返回0来通知应用层另一端已经终止了向本端的数据传送

发送FIN通常是应用层对socket进行关闭的结果

Num05-->TCP协议的2MSL问题

这里写图片描述

加以说明:

1,2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态。

2,当TCP的一端发起主动关闭,在发出最后一个ACK包后,

3,即第3次握 手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,

4,必须在此状态上停留两倍的MSL时间,

5,等待2MSL时间主要目的是怕最后一个 ACK包对方没收到,

6,那么对方在超时后将重发第三次握手的FIN包,

7,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。

8,在TIME_WAIT状态 时两端的端口不能使用,要等到2MSL时间结束才可继续使用。

9,当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。

10,不过在实际应用中可以通过设置 SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

Num06-->TCP协议长链接和短链接

TCP在真正的读写操作之前,server与client之间必须建立一个连接,

当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,

连接的建立通过三次握手,释放则需要四次握手,

所以说每个连接的建立都是需要资源消耗和时间消耗的。

Test01-->长链接

1, client 向 server 发起连接

2,server 接到请求,双方建立连接

3,client 向 server 发送消息

4,server 回应 client

5,一次读写完成,连接不关闭

6,后续读写操作...

7,长时间操作之后client发起关闭请求

Test02-->短链接

1,client 向 server 发起连接请求

2,server 接到请求,双方建立连接

3,client 向 server 发送消息

4,server 回应 client

5,一次读写完成,此时双方任何一个都可以发起 close 操作

Test03-->长链接和短链接的区别

长链接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。

对于频繁请求资源的客户来说,较适用长连接。

client与server之间的连接如果一直不关闭的话,会存在一个问题,

随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,

如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;

如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。

短链接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。

Test04-->TCP长/短链接的应用场景

长链接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。

每个TCP连接都需要三次握手,这需要时间,如果每个操作都是先连接,

再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,

再次处理时直接发送数据包就OK了,不用建立TCP连接。

例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

像WEB网站的HTTP服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源。

像WEB网站这么频繁的成千上万甚至上亿客户端的连接,用短连接会更省一些资源;如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。虽然并发量大,但每个用户无需频繁操作情况下需用短连好。

Num07-->TCP并发服务器--多进程实现

通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服务。当客户端不是特别多的时候,这种方式还行,如果有几百上千个,就不可取了,因为每次创建进程等过程需要好较大的资源。

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

from multiprocessing import Process

from socket import *

# 需要为客户端提供服务

def do_service(connect_socket):

while True:

recv_data = connect_socket.recv(1024)

if len(recv_data) == 0:

# 发送方关闭tcp的连接,recv()不会阻塞,而是直接返回''

# print('client %s close' % str(client_addr))

# s.getpeername() s.getsockname()

print('client %s close' % str(connect_socket.getpeername()))

break

print('recv: %s' % recv_data.decode('gbk'))

def main():

# 1.创建socket

listen_socket = socket(AF_INET, SOCK_STREAM)

# stream流式套接字,对应tcp

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址,不用等2msl, 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 2.绑定端口

my_addr = ('192.168.105.125', 8080)

listen_socket.bind(my_addr)

# 3,接听状态

listen_socket.listen(4) # 设置套接字成监听,4表示一个己连接队列长度

print('listening...')

# 4.等待客户端来请求

# 父进程只专注接受连接请求

while True:

# 接受连接请求,创建连接套接字,用于客户端间通信

connect_socket, client_addr = listen_socket.accept() # accept默认会引起阻塞

# 新创建连接用的socket, 客户端的地址

# print(connect_socket)

print(client_addr)

# 每当来新的客户端连接,创建子进程,由子进程和客户端通信

process_do_service = Process(target=do_service, args=(connect_socket,))

process_do_service.start()

# 父进程,关闭connect_socket

connect_socket.close()

if __name__ == "__main__":

main()

Num08-->TCP并发服务器--多线程实现

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

from socket import *

from threading import Thread

# 需要为客户端提供服务

def do_service(connect_socket):

while True:

recv_data = connect_socket.recv(1024)

if len(recv_data) == 0:

# 发送方关闭tcp的连接,recv()不会阻塞,而是直接返回''

# print('client %s close' % str(client_addr))

# s.getpeername() s.getsockname()

print('client %s close' % str(connect_socket.getpeername()))

break

print('recv: %s' % recv_data.decode('gbk'))

def main():

# 1.创建socket

listen_socket = socket(AF_INET, SOCK_STREAM)

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址,不用等2msl 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 2.绑定端口

my_addr = ('192.168.105.125', 8080)

# shift + insert

listen_socket.bind(my_addr)

# 3.接听状态

listen_socket.listen(4) # 设置套接字成监听,4表示一个己连接队列长度

print('listening...')

# 4.等待来电话

# 主线程只专注接受连接请求

while True:

# 接受连接请求,创建连接套接字,用于客户端连通信

connect_socket, client_addr = listen_socket.accept() # accept默认会引起阻塞

# 新创建连接用的socket, 客户端的地址

# print(connect_socket)

print(client_addr)

# 每当来新的客户端连接,创建子线程,由子线程和客户端通信

thread_do_service = Thread(target=do_service, args=(connect_socket,))

thread_do_service.start()

# 主线程,不能关闭connect_socket,多个线程共享打开的文件

# connect_socket.close()

if __name__ == "__main__":

main()

Num09-->TCP单进程阻塞服务器实现

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

import time

from socket import *

def main():

# 1.创建socket

listen_socket = socket(AF_INET, SOCK_STREAM)

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 2.绑定端口

my_addr = ('192.168.105.125', 8080)

listen_socket.bind(my_addr)

# 3.接听状态

listen_socket.listen(4)

print('listening...')

# 4.等待客户端发起请求

while True:

# 接受连接请求,创建连接套接字,用于客户端间通信

connect_socket, client_addr = listen_socket.accept() # accept默认会引起阻塞

# 新创建连接用的socket, 客户端的地址

# print(connect_socket)

print(client_addr)

while True:

# tcp recv() 只会返回接收到的数据

recv_data = connect_socket.recv(1024)

if len(recv_data) == 0:

# 发送方关闭tcp的连接,recv()不会阻塞,而是直接返回''

print('client %s close' % str(client_addr))

time.sleep(5)

break

print('recv: %s' % recv_data.decode('gbk'))

# 用完之后,关闭connect_socket

connect_socket.close()

if __name__ == "__main__":

main()

Num10-->TCP单进程非阻塞服务器实现

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

import time

from socket import *

def main():

# 1.创建socket

listen_socket = socket(AF_INET, SOCK_STREAM)

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 设置listen_socket为非阻塞方式

listen_socket.setblocking(False) # 设置非阻塞

# 2.绑定端口

my_addr = ('192.168.105.125', 8080)

listen_socket.bind(my_addr)

# 3.接听状态

listen_socket.listen(4)

print('listening...')

# 4.等待客户端发起请求

# 创建一个列表,保存已连接socket

connect_socket_list = []

while True:

print(connect_socket_list)

try:

# 接受连接请求,创建连接套接字,用于客户端连通信

connect_socket, client_addr = listen_socket.accept() # accept默认会引起阻塞

except Exception as e: # 还没有客户端连接

# print(e)

# time.sleep(1)

pass

else: # 此时有连接请求

# 新创建连接用的socket, 客户端的地址

print('有新的客户端连接 %s' % str(client_addr))

# 将新socket 设成非阻塞

connect_socket.setblocking(False)

# 将新的socket添加到列表中,以便后续循环读数据

connect_socket_list.append(connect_socket)

# 保存删除socket列表

need_delete_socket_list = []

# 遍历已连接的socket分别读数据

for new_socket in connect_socket_list:

try:

recv_data = new_socket.recv(1024)

except:

pass

else:

# 如果对方关闭

if len(recv_data) == 0:

print('%s close' % (str(new_socket.getpeername())))

new_socket.close()

# 从connect_socket_list列表中删除,单独使用列表保存要删除socket

need_delete_socket_list.append(new_socket)

continue

print('from %s : %s' %

(str(new_socket.getpeername()), recv_data.decode('gbk')))

# 从connect_socket_list删除已关闭soccket

for s in need_delete_socket_list:

connect_socket_list.remove(s)

time.sleep(1)

if __name__ == "__main__":

main()

Num11-->select版--TCP服务器实现

Test01-->select 原理

在多路复用的模型中,比较常用的有select模型和epoll模型。这两个都是系统接口,由操作系统提供。当然,Python的select模块进行了更高级的封装。

网络通信被Unix系统抽象为文件的读写,通常是一个设备,由设备驱动程序提供,驱动可以知道自身的数据是否可用。支持阻塞操作的设备驱动通常会实现一组自身的等待队列,如读/写等待队列用于支持上层(用户层)所需的block或non-block操作。设备的文件的资源如果可用(可读或者可写)则会通知进程,反之则会让进程睡眠,等到数据到来可用的时候,再唤醒进程。

这些设备的文件描述符被放在一个数组中,然后select调用的时候遍历这个数组,如果对于文件描述符可读则会返回该文件描述符。当遍历结束之后,如果仍然没有一个可用设备文件描述符,select则让用户进程睡眠,直到等待资源可用的时候再唤醒,唤醒之后遍历之前那个监视的数组。每次遍历都是依次进行判断的。

Test02-->select的优缺点

优点:select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。

缺点:select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.

对socket进行扫描时是依次扫描的,即采用轮询的方法,效率较低。

当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。

Test03-->案例的实现代码

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

import select

import sys # sys.stdin 代表键盘设备的文件对象

from socket import *

def main():

# 1.创建socket

listen_socket = socket(AF_INET, SOCK_STREAM)

# 设置允许复用地址,当建立连接之后服务器先关闭,设置地址复用

# 设置socket层属性 复用地址 允许

listen_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 2.绑定端口

my_addr = ('192.168.105.125', 8080)

listen_socket.bind(my_addr)

# 3.接听状态

listen_socket.listen(4)

print('listening...')

# 指定select关心的哪些路(socket,或文件)数据

rlist = [listen_socket, sys.stdin] # 要读的文件对象列表,包括listen socket

wlist = [] # 要写的文件对象列表

xlist = [] # 出现异常的文件对象列表

while True:

print(rlist)

# select 会阻塞等待三个列表中文件对象就绪,如果没就绪,select一直阻塞;只有任意文件就绪,select返回

# 就绪的文件列表

read_ready_list, wready, excplist = select.select(rlist, wlist, xlist)

# 指定seclet关注读,写,异常文件列表

# 如果select返回,一定有客户端连接服务器

# 循环判断是哪个关注的文件,读就绪了

for fobj in read_ready_list:

# 如果fobj是listen_socket对象,一定有客户端连接服务器

if fobj == listen_socket:

new_socket, peer_addr = fobj.accept() # 此时accept调用一定不会阻塞

print(peer_addr)

# 将新的socket添加至rlist,也要进行关注

rlist.append(new_socket)

elif fobj == sys.stdin: # 键盘有数据输入

data = sys.stdin.readline() # input()

print('input %s' % data)

if data == 'quit\n':

exit()

else: # 已连接socket有数据可读

recv_data = fobj.recv(1024)

if len(recv_data) > 0:

print('from %s : %s' % (str(fobj.getpeername()), recv_data.decode('gbk')))

else: # 客户端关闭socket

print('%s close' % str(fobj.getpeername()))

fobj.close() # 将关闭socket从rlist列表中删除,表示不再关注这个socket

rlist.remove(fobj)

if __name__ == "__main__":

main()

Num12-->epoll版--TCP服务器实现

Test01-->epoll的优点:

没有最大并发连接的限制,能打开的FD(指的是文件描述符,通俗的理解就是套接字对应的数字编号)的上限远大于1024

效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。

Test02-->一些术语

EPOLLIN (可读)

EPOLLOUT (可写)

EPOLLET (ET模式)

epoll对文件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。

LT模式是默认模式,LT模式与ET模式的区别如下:

LT模式:当epoll检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll时,会再次响应应用程序并通知此事件。

ET模式:当epoll检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll时,不会再次响应应用程序并通知此事件。

Test03-->案例的实现代码

#! /usr/bin/env python3

# -*- coding:utf-8 -*-

# @Author : xiaoke

import socket

import select

# 创建套接字

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 设置可以重复使用绑定的信息

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 绑定本机信息

s.bind(("", 8080))

# 变为被动

s.listen(10)

# 创建一个epoll对象

epoll = select.epoll()

# 测试,用来打印套接字对应的文件描述符

# print s.fileno()

# print select.EPOLLIN|select.EPOLLET

# 注册事件到epoll中

# epoll.register(fd[, eventmask])

# 注意,如果fd已经注册过,则会发生异常

# 将创建的套接字添加到epoll的事件监听中

epoll.register(s.fileno(), select.EPOLLIN | select.EPOLLET)

connections = {}

addresses = {}

# 循环等待客户端的到来或者对方发送数据

while True:

# epoll 进行 fd 扫描的地方 -- 未指定超时时间则为阻塞等待

epoll_list = epoll.poll()

# 对事件进行判断

for fd, events in epoll_list:

# print fd

# print events

# 如果是socket创建的套接字被激活

if fd == s.fileno():

conn, addr = s.accept()

print('有新的客户端到来%s' % str(addr))

# 将 conn 和 addr 信息分别保存起来

connections[conn.fileno()] = conn

addresses[conn.fileno()] = addr

# 向 epoll 中注册 连接 socket 的 可读 事件

epoll.register(conn.fileno(), select.EPOLLIN | select.EPOLLET)

elif events == select.EPOLLIN:

# 从激活 fd 上接收

recvData = connections[fd].recv(1024)

if len(recvData) > 0:

print('recv:%s' % recvData)

else:

# 从 epoll 中移除该 连接 fd

epoll.unregister(fd)

# server 侧主动关闭该 连接 fd

connections[fd].close()

print("%s---offline---" % str(addresses[fd]))

python读数据库的通信协议是什么_Python中TCP协议的理解相关推荐

  1. python读数据库的通信协议是_Python以太坊区块链交互将数据存入数据库

    关于区块链介绍性的研讨会通常以易于理解的点对点网络和银行分类账这类故事开头,然后直接跳到编写智能合约,这显得非常突兀.因此,想象自己走进丛林,想象以太坊区块链是一个你即将研究的奇怪生物.今天我们将观察 ...

  2. python读数据库的通信协议是,Python操作SQLite数据库过程解析

    SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统. 不像常见的客户-服务器范例,SQLite引擎不是个程序与之通信的独立进程,而是连接到程序中成为它的一个主要部分.所以主要的通信协 ...

  3. python tcp处理_python中TCP粘包问题解决方案

    TCP协议中的粘包问题 1.粘包现象 基于TCP写一个远程cmd功能 #服务端 importsocketimportsubprocess sever=socket.socket() sever.bin ...

  4. python更新数据库表的时间字段_python更新数据库中某个字段的数据(方法详解)

    连接数据库基本操作,我把每一步的操作是为什么给大家注释一下,老手自行快进. 请注意这是连接数据库操作,还不是更新. import pymysql #导包 #连接数据库 db = pymysql.con ...

  5. python 不安全的包或方法_Python中的10个常见安全漏洞及修复方法

    写安全的代码很困难,当你学习一门编程语言.一个模块或框架时,你会学习其使用方法.在考虑安全性时,你需要考虑如何避免代码被滥用,Python也不例外,即使在标准库中,也存在着许多糟糕的实例.然而,许多 ...

  6. python用保留字while实现无限循环_Python中无限循环需要什么条件

    无限循环 如果条件判断语句永远为 true,循环将会无限的执行下去. 如下实例 #!/usr/bin/python # -*- coding: UTF-8 -*- var = 1 while var ...

  7. python新式类和经典类区别_Python中新式类和经典类的区别,钻石继承

    1)首先,写法不一样: class A: pass class B(object): 2)在多继承中,新式类采用广度优先搜索,而旧式类是采用深度优先搜索. 3)新式类更符合OOP编程思想,统一了pyt ...

  8. __init__在python中的用法知乎_python中对_init_的理解及实例解析 python为什么要有一个init函数 知乎...

    Python中"__init__"的意义是什么? Python中__init__的意义依偎着你心跳声如此频繁,就算世界末日小编也会嚣张的笑. 测试人员学python时,应该如何理解 ...

  9. python mysql数据库操作grid控件_Python学习笔记_02:使用Tkinter连接MySQL数据库实现登陆注册功能...

    1 环境搭建 1.1 Python安装 本文具体实现部分Python环境:Python2.7.14,64位版本 附:配置PythonIDE,推荐PyCharm(具体IDE界面见下图),下载点击运行即可 ...

  10. python读取数据库文件的扩展名_Python读取sqlite数据库文件的方法分析

    本文实例讲述了Python读取sqlite数据库文件的方法.分享给大家供大家参考,具体如下: 这是Python内置的,不需要pip install 包 数据库里面有很多张表 要操作数据库首先要连接co ...

最新文章

  1. 用于区分IE的:条件注释
  2. element菜单默认展开和选中
  3. opencv图像识别
  4. cocosStudio制作ScrollView并在cocos2dx 3.0中使用。
  5. python docx表格宽度_RPA手把手——python-docx 设置 word 文档中表格格式
  6. redis配置master-slave模式
  7. ECM之ucf session wait timeout【DFC_ACS_LOG_NO_NL】问题分析
  8. Windows服务器上使用phpstudy部署PHP程序
  9. 弹性屋顶涂料行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  10. linux tcp文件分包_在Linux下基于TCP协议的文件传输程序.
  11. Nagios安装配置教程(二)环境搭建
  12. linux下的osd服务,OSD通知来到GNOME Shell
  13. 车牌识别程序_在线的,离线的车牌识别
  14. 【交叉编译】配置交叉编译工具链
  15. vrep中接近开关与激光雷达
  16. stateflow之学习——01
  17. lrzsz的交叉编译与使用
  18. 计算机无法安装u盘驱动,电脑上插入u盘提示未能成功安装设备驱动程序怎么修复...
  19. 项目实战 - tpshop商城项目环境搭建
  20. 网络安全法及个人信息法律解读

热门文章

  1. 各行业的英语术语(绝对精华 2)
  2. DOS命令:format
  3. 零电压开关(ZVS)电路原理与设计(整理)
  4. 动态网站数据采集 - 时光网电影信息爬虫
  5. 【FL攻防综述】Privacy and Robustness in Federated Learning: Attacks and Defenses
  6. VMwareESX常用命令和IP地址修改
  7. 无刷直流电动机矢量控制(五)——开环调速原理(方波形式)
  8. 【数据挖掘算法竞赛】山东省-公积金贷款逾期预测TOP8 baseline523
  9. 由于授权协议中一个错误,远程计算机中断了会话。请重新跟远程计算机连接;或者跟服务器管理员联系。
  10. .net mvc 文件压缩打包下载