一、软件开发的架构

1: C/S架构

Client与Server  客户端与服务器端,这里的客户端一般泛指客户端应用EXE,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。

2: B/S架构

Browser与Server  浏览器端与服务器端。

Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要去安装什么应用程序,只需在浏览器上通过HTTP请求服务器端相关的资源。

二、网络基础

IP地址:指互联网协议地址。

IP地址是IP协会提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

IP地址是一个32位的二进制数,通常被分割为4个‘8位二进制数’。

IP地址通常用“点分十进制”表示(a,b,c,d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。

端口可以认为是设备与外界通讯交流的出口。

因此IP地址可以精确到具体的一台电脑,而端口精确到具体的程序。

通过子网掩码,我们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个位数都是1,则结果1,反之0),然后比较结果是否相同,如果是的话,就表示它们在同一个子网络中,否则就不是。

总结一下,IP协议的作用主要有两个:一个是为每一台计算机分配IP地址,另一个是确定哪些地址在同一个子网络。

TCP协议

TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户与服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传输到另一端。

可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK[1],并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接。[1]

TCP三次握手的过程如下:

客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。

服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。

客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。

三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。

tcp的三次握手

建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由TCP的半关闭(half-close)造成的。

(1) 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。

(2) 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。

注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。

(3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。

(4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。[1]

既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。

注意:

(1) “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。[2]

(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。

(3) 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。

无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。[2]

tcp的四次挥手

UDP协议

UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层

每层运行常见的物理设备

传输层——> 四层交换机、四层的路由器

网络层——>路由器、三层交换机

数据链路层——>网桥、以太网交换机、网卡

物理层——>中继器、集线器、双绞线

每层运行常见的协议

应用层——>。。。

传输层——>TCP与UDP协议

网络层——>ip协议

数据链路层——>arp协议   (通过ip找mac地址)

物理层——>。。。

交换机:广播 单播 组播

ip协议:ip地址的格式

# ip地址 一台机器在一个网络内唯一的标识

# 子网掩码  ip地址与子网掩码做按位与运算,得到的结果是网段

# 网关ip 局域网内的机器访问公网ip,就通过网关访问

三、socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

socket和file的区别:

1:file模块是针对某个指定文件进行打开、读写、关闭

2:socket模块是针对服务器端和客户端socket进行打开、读写、关闭

基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

基于TCP协议的socket

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

importsocket

sk=socket.socket()

sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字

sk.listen() #监听链接

conn,addr = sk.accept() #接受客户端链接

ret = conn.recv(1024) #接收客户端信息

print(ret) #打印客户端信息

conn.send(b'hi') #向客户端发送信息

conn.close() #关闭客户端套接字

sk.close() #关闭服务器套接字(可选)

服务端

importsocket

sk= socket.socket() #创建客户套接字

sk.connect(('127.0.0.1',8898)) #尝试连接服务器

sk.send(b'hello!')

ret= sk.recv(1024) #对话(发送/接收)

print(ret)

sk.close()#关闭客户套接字

客户端

tcp实现与多个客户端通信,必须结束一个客户端,才能到下一个客户端。

#服务器端

importsocket#tcp协议

sk = socket.socket() #创建一个socket对象

sk.bind(('127.0.0.1',8080)) #给server端绑定一个ip和端口

sk.listen()whileTrue:

conn,addr=sk.accept()whileTrue:

msg= conn.recv(1024).decode('utf-8') #阻塞,直到收到一个客户端发来的消息

print(msg)if msg == 'bye':breakinfo= input('>>>')if info == 'bye':

conn.send(b'bye')breakconn.send(info.encode('utf-8')) #发消息

conn.close() #关闭连接

sk.close() #关闭socket对象,如果不关闭,还能继续接收

#客户端1

importsocket

sk=socket.socket()

sk.connect(('127.0.0.1',8080))whileTrue:

msg= input('>>>')if msg == 'bye':

sk.send(b'bye')breaksk.send(msg.encode('utf-8'))

ret= sk.recv(1024).decode('utf-8')if ret == 'bye':break

print(ret)

sk.close()#客户端2

importsocket

sk=socket.socket()

sk.connect(('127.0.0.1',8080))whileTrue:

msg= input('client2:>>>')if msg == 'bye':

sk.send(b'bye')breaksk.send(('client2 :'+msg).encode('utf-8'))

ret= sk.recv(1024).decode('utf-8')if ret == 'bye':break

print(ret)

sk.close()

tcp服务器与多个客户端通信

基于udp协议的socket

#服务器端

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM) #DGRAM datagram

sk.bind(('127.0.0.1',8080)) #只有服务端有的

msg,addr= sk.recvfrom(1024)print(msg.decode('utf-8'))

sk.sendto(b'bye',addr)

sk.close()#udp的server 不需要进行监听也不需要建立连接#在启动服务之后只能被动的等待客户端发送消息过来#客户端发送消息的同时还会 自带地址信息#消息回复的时候 不仅需要发送消息,还需要把对方的地址填写上

#客户端

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

ip_port= ('127.0.0.1',8080)

sk.sendto(b'hello',ip_port)

ret,addr= sk.recvfrom(1024)print(ret.decode('utf-8'))

sk.close()#client端不需要connect 因为UDP协议是不需要建立连接的#直接了解到对方的ip和端口信息就发送数据就行了#sendto和recvfrom的使用方法是完全和server端一致的

#client端不需要connect 因为UDP协议是不需要建立连接的#直接了解到对方的ip和端口信息就发送数据就行了#sendto和recvfrom的使用方法是完全和server端一致的

基于udp协议的socket

#服务器端

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

sk.bind(('127.0.0.1',8080))whileTrue:

msg,addr= sk.recvfrom(1024)print(addr)print(msg.decode('utf-8'))

info= input('>>>').encode('utf-8')

sk.sendto(info,addr)

sk.close()#客户端1

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

ip_port= ('127.0.0.1',8080)whileTrue:

info= input('tiger :')

info= ('\033[34m来自tiger的消息 :%s\033[0m'%info).encode('utf-8')

sk.sendto(info,ip_port)

msg,addr= sk.recvfrom(1024)print(msg.decode('utf-8'))

sk.close()#客户端2

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

ip_port= ('127.0.0.1',8080)whileTrue:

info= input('二哥 :')

info= ('\033[32m来自二哥的消息 :%s\033[0m'%info).encode('utf-8')

sk.sendto(info,ip_port)

msg,addr= sk.recvfrom(1024)print(msg.decode('utf-8'))

sk.close()

QQ聊天

#服务器端

importtimeimportsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

sk.bind(('127.0.0.1',8090))whileTrue:

strf,addr= sk.recvfrom(1024)

strf= strf.decode('utf-8')

res= time.strftime(strf).encode('utf-8')

sk.sendto(res,addr)

sk.close()#客户端

importsocket

sk= socket.socket(type=socket.SOCK_DGRAM)

addr= ('127.0.0.1',8090)

info= input('>>>').encode('utf-8')

sk.sendto(info,addr)

ret,addr= sk.recvfrom(1024)print(ret.decode('utf-8'))

sk.close()

格式化时间

服务端套接字函数

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()   得到阻塞套接字操作的超时时间

面向文件的套接字的函数

s.fileno()    套接字的文件描述符

s.makefile()     创建一个与该套接字相关的文件

四、黏包

黏包:同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包。

只有TCP有黏包现象,UDP永远不会黏包:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少个字节的数据所造成的。

用UDP协议发送时,用sendto函数最大能发送数据的长度为:65535- IP头(20) – UDP头(8)=65507字节。用sendto函数发送数据时,如果发送数据长度大于该值,则函数会返回错误。(丢弃这个包,不进行发送)

用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小),这是指在用send函数时,数据长度参数不受限制。而实际上,所指定的这段数据并不一定会一次性发送出去,如果这段数据比较长,会被分段发送,如果比较短,可能会等待和下一次数据一起发送。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

会发生黏包的两种情况:

1、发送方的缓存机制

发送端需要等缓冲区满才发送出去,造成黏包(发送数据时间间隔很短,数据量很小,会合到一起,产生黏包)

importsocket

ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen()

conn,addr=tcp_socket_server.accept()

data1=conn.recv(10)

data2=conn.recv(10)print('----->',data1.decode('utf-8'))print('----->',data2.decode('utf-8'))

conn.close()

服务端

importsocket

BUFSIZE=1024ip_port=('127.0.0.1',8080)

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

res=s.connect_ex(ip_port)

s.send('hello'.encode('utf-8'))

s.send('egg'.encode('utf-8'))

客户端

2、接收方的缓存机制

接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生黏包)

importsocket

ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen(5)

conn,addr=tcp_socket_server.accept()

data1=conn.recv(2) #一次没有收完整

data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

print('----->',data1.decode('utf-8'))print('----->',data2.decode('utf-8'))

conn.close()

服务端

importsocket

BUFSIZE=1024ip_port=('127.0.0.1',8080)

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

res=s.connect_ex(ip_port)

s.send('hello egg'.encode('utf-8'))

客户端

黏包的解决方案

方案一

importsocket

sk=socket.socket()

sk.bind(('127.0.0.1',8080))

sk.listen()

conn,addr=sk.accept()whileTrue:

cmd= input('>>>')if cmd == 'q':

conn.send(b'q')breakconn.send(cmd.encode('gbk'))

num= conn.recv(1024).decode('utf-8') #2048

conn.send(b'ok')

res= conn.recv(int(num)).decode('gbk')print(res)

conn.close()

sk.close()

服务端

importsocketimportsubprocess

sk=socket.socket()

sk.connect(('127.0.0.1',8080))whileTrue:

cmd= sk.recv(1024).decode('gbk')if cmd == 'q':breakres= subprocess.Popen(cmd,shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE)

std_out=res.stdout.read()

std_err=res.stderr.read()

sk.send(str(len(std_out)+len(std_err)).encode('utf-8')) #2000

sk.recv(1024) #ok

sk.send(std_out)

sk.send(std_err)

sk.close()#好处:确定了我到底要接收多大的数据

#要在文件中配置一个配置项 : 就是每一次recv的大小 buffer = 4096

#当我们要发送大数据的时候 ,要明确的告诉接收方要发送多大的数据,以便接收方能够准确的接收到所有数据

#多用在文件传输的过程中

#大文件的传输 一定是按照字节读 每一次读固定的字节

#传输的过程中 一边读一边传 接收端 一边收一边写

#不好的地方:多了一次交互#send sendto 在超过一定范围的时候 都会报错#程序的内存管理

客户端

方案二

借用struct模块,该模块可以把一个类型,如数字,转成固定长度的bytes。我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度。

发送时:

先发送struct转换好的数据长度4字节;再发送数据。

接收时:

先接受4个字节使用struct转换成数字来获取要接收的数据长度;再按照长度接收数据。

importsocket,struct,jsonimportsubprocess

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

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

phone.bind(('127.0.0.1',8080))

phone.listen(5)whileTrue:

conn,addr=phone.accept()whileTrue:

cmd=conn.recv(1024)if not cmd:break

print('cmd: %s' %cmd)

res=subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE)

err=res.stderr.read()print(err)iferr:

back_msg=errelse:

back_msg=res.stdout.read()

conn.send(struct.pack('i',len(back_msg))) #先发back_msg的长度

conn.sendall(back_msg) #在发真实的内容

conn.close()

服务端(自定制报头)

importsocket,time,struct

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

res=s.connect_ex(('127.0.0.1',8080))whileTrue:

msg=input('>>:').strip()if len(msg) == 0:continue

if msg == 'quit':breaks.send(msg.encode('utf-8'))

l=s.recv(4)

x=struct.unpack('i',l)[0]print(type(x),x)#print(struct.unpack('I',l))

r_s=0

data=b''

while r_s

r_d=s.recv(1024)

data+=r_d

r_s+=len(r_d)#print(data.decode('utf-8'))

print(data.decode('gbk')) #windows默认gbk编码

客户端(自定制报头)

也可以把报头坐车字典,字典里包含将要发送的真实数据的详细信息,然后json序列化,再用struct将序列化后的数据长度打包成4个字节。

发送时:

先发报头长度;再编码报头内容然后发送;最后发真实内容。

接收时:

先接收报头长度,用struct取出来;根据取出的长度收取报头内容,然后解码,反序列化;最后从反序列化的结果中取出待取数据的详细信息,最后去取真实的数据内容。

importsocket,struct,jsonimportsubprocess

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

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

phone.bind(('127.0.0.1',8080))

phone.listen()whileTrue:

conn,addr=phone.accept()whileTrue:

cmd=conn.recv(1024)if not cmd:break

print('cmd: %s' %cmd)

res=subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE)

err=res.stderr.read()print(err)iferr:

back_msg=errelse:

back_msg=res.stdout.read()

headers={'data_size':len(back_msg)}

head_json=json.dumps(headers)

head_json_bytes=bytes(head_json,encoding='utf-8')

conn.send(struct.pack('i',len(head_json_bytes))) #先发报头的长度

conn.send(head_json_bytes) #再发报头

conn.sendall(back_msg) #在发真实的内容

conn.close()

服务端

importsocketimportstruct,json

ip_port=('127.0.0.1',8080)

client=socket(AF_INET,SOCK_STREAM)

client.connect(ip_port)whileTrue:

cmd=input('>>:')if not cmd:continueclient.send(bytes(cmd,encoding='utf-8'))

head=client.recv(4)

head_json_len=struct.unpack('i',head)[0]

head_json=json.loads(client.recv(head_json_len).decode('utf-8'))

data_len=head_json['data_size']

recv_size=0

recv_data=b''

while recv_size

recv_data+=client.recv(1024)

recv_size+=len(recv_data)print(recv_data.decode('utf-8'))#print(recv_data.decode('gbk')) #windows默认gbk编码

客户端

python的网络编程用途_python---网络编程相关推荐

  1. python网络编程知识点_python 网络编程要点

    From http://www.zhihu.com/question/19854853 Python网络编程是一个很大的范畴,个人感觉需要掌握的点有: 1. 如何使用Python来创建socket, ...

  2. python网络通信传输的数据类型_Python网络编程中的网络数据和网络错误。

    上一个章节我们说的是套接字名和DNS.这篇文章我们主要解决下面问题. 我们在两台主机之间建立与关闭TCP流连接以及UDP数据报连接后.我们应该怎么准备我们需要传输的数据,该怎么对数据进行编码与格式化. ...

  3. python网络编程自学_Python网络编程学习_Day11

    一.协程 1.理论知识 协程,又称伪线程,是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈. ...

  4. python核心编程电子书_Python核心编程 PDF 超清第3版

    给大家带来的一篇关于Python编程相关的电子书资源,介绍了关于Python编程.Python核心编程方面的内容,本书是由人民邮电出版社出版,格式为PDF,资源大小22.4 MB,卫斯理编写,目前豆瓣 ...

  5. python网络爬虫应用_python网络爬虫应用实战

    原标题:python网络爬虫应用实战 Python这门编程语言包罗万象,可以说掌握了python,除了一些特殊环境和高度的性能要求,你可以用它做任何事. Python作为一门脚本语言,它灵活.易用.易 ...

  6. python开发网络小工具_python 网络工具

    书籍:掌握Python的网络和安全 Mastering Python for Networking and Security - 2018.pdf 简介 掌握Python的网络和安全 掌握Python ...

  7. python网络编程案例_Python 网络编程_python网络编程基础_python高级编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  8. python网络编程教学_python网络编程学习初步

    重剑点评: 真简单明了!复习网络编程,顺便学习python. 一.套接字 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象 ...

  9. python网络通信编程实例_python网络编程之数据传输UDP实例分析

    本文实例讲述了python网络编程之数据传输UDP实现方法.分享给大家供大家参考.具体分析如下: 一.问题: 你觉得网络上像msn,qq之类的工具在多台机器之间互相传输数据神秘吗?你也想玩一下在两台机 ...

最新文章

  1. mysql pos点是什么,MySQL 5.6 主从报错一例
  2. webService 使用CXF 实现简单的helloworld
  3. 音频处理四:(音频的分帧)
  4. Python爬虫开发:贴吧案例
  5. 自学编程需要注意什么?
  6. Dijkstra-解决最短路径问题
  7. Q111:PBRT-V3系统概述
  8. 【Python56--爬取妹子图】
  9. JAVA自学之路马士兵教程观看顺序
  10. C语言常见问题(4):Collapsible if statements should be merged
  11. 笔记本电脑Haswell黑苹果opencore睡眠实战
  12. RK3288开发板——Debian8系统制作
  13. 腾讯信鸽自定义推送通知
  14. 1040 有几个PAT (25 分)
  15. 在U盘上安装debian linux
  16. Electron flash插件
  17. 分类模型评价指标说明
  18. sql2000密码查看方式
  19. 英雄联盟手游推荐耳机,南卡Lite Pro 2展现优秀游戏声效处理硬实力
  20. VMD分解,matlab代码,包络线,包络谱,中心频率,峭度值,能量熵,近似熵,包络熵,频谱图,希尔伯特变换,包含所有程序MATLAB代码,-西储大学数据集为例

热门文章

  1. 图书馆借阅数据分析系统设计与实现
  2. eps倾斜摄影矢量化采集毕业设计_干货 | 6款倾斜摄影裸眼3D采集软件推荐给大家...
  3. 四轴六轴机械臂基础运动仿真实验(Matlab)
  4. KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解
  5. 2012微软暑期实习笔试
  6. zedboard_第一篇blog
  7. 华章计算机拍了拍你,并送来了8月书单(上)
  8. DVD Cloner 2021 for Mac(DvD刻录软件)
  9. [旧文]图解nlite精简XP全过程
  10. 小曾曾读书笔记 ||《大数据实践之路》