查看Python中支持的编码方式:https://docs.python.org/3/library/codecs.html?highlight=utf
IP地址工具:http://ipblock.chacuo.net/
查看应用程序进程PID:
1.启动任务管理器,点击进程:默认是这样的:
2.点击查看, 选择列,勾上PID即可。
进程PID与进程使用的端口号是不同的概念。
Windows下看看哪个端口被占用及占用的进程
命令:
netstat -aon | findstr "8080"
netstat -an#查看所有的端口使用情况8080是要查看的端口号。
例如在pycharm中建立一个网络通信
#time_server.py
import socket
import time
HOST = '127.0.0.1'
PORT = 12345
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpServerSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpServerSock.bind(ADDR)
tcpServerSock.listen(5)
while True:
print("waiting for connection...")
#这里tcpClietnSock为,包含了socket的信息
tcpClientSock,addr = tcpServerSock.accept()
print("...connected from:",addr)
while True:
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
# tcpClientSock.send('[%s] %s'%(time.ctime().encode('utf-8'),str(data).encode('utf-8')))
# tcpClientSock.send('%s %s'%(time.ctime().encode('utf-8'),data))
tcpClientSock.send(bytes("[%s] %s"%(time.ctime(),data.decode('utf-8')),encoding='utf-8'))
tcpClientSock.close()
#time_client.py
import socket
HOST = '127.0.0.1'
PORT = 12345
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpClientSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpClientSock.connect(ADDR)
while True:
data = input('>')
if not data:
break
tcpClientSock.send(bytes(data,encoding='utf-8'))
# tcpClientSock.send(data.encode('utf-8'))
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
print(data.decode('utf-8'))
tcpClientSock.close()
服务器端使用的端口好为:12345,运行服务器和客户端后,发现客户端使用的端口号为12037,执行命令:
查看到端口12345和12037被占用了,在任务管理其中查看到是Python3占用了这两个端口
为什么使用端口,而不直接使用PID了?
PID也可以唯一表示一个进程呀,这是因为使用PID代价太大,双方通信之前,得需要提前知道对方的PID,但是PID是操作系统自动分配的,人工去查很麻烦。如果直接使用端口的话比较方便,一般一个服务的端口比较固定。
同一个系统中,端口不能重复。
通信调试助手:模拟发送和接收情况。链接:https://pan.baidu.com/s/1GJTYxvUKGIHB9KM-D0CVug 密码:31z1
TCP连接中listen参数问题:
连接队列长度:客户端已经和服务器建立连接,或者客户端正在和服务器建立连接,但是还没有被服务器accept的最大个数。即同时等待accept的个数,和已经accept的个数没有关系。
Windows和Mac中严格安装这个参数来,Linux中内核会自己处理。
服务器
from socket import *
import time
s = socket(AF_INET,SOCK_STREAM)
s.bind(("127.0.0.1",12345))
s.listen(5)#队列缓存
while True:
clientScoket,addr = s.accept()
print(addr)
time.sleep(1)客户端
from socket import *
for i in range(10):
c = socket(AF_INET, SOCK_STREAM)
c.connect(("127.0.0.1",12345))#客户端只管啪啪啪connect,等连不上就报错
print(i)
服务器端处理过慢,可能导致客户端连接超时报错。
本地的进程间通信:
网络间通信:socket
AF_UNIX | 本地通信 |
AF_INET | IPv6 |
AF_NETLINK | |
SOCK_STREAM | TCP |
SOCK_DGRAM | UDP |
UDP在局域网中几乎不会丢包
Python3中发送数据需要bytes类型,不能是字符串类型,不然会报错:
发送前将字符串编码,接收后将字符串解码。
中文一般是UTF-8,或者gb2312。
data='hello world'
data.encode('utf-8')
b'hello world'
bytes(data,encoding='utf-8')
b'hello world'
data='黄铁牛'
data.encode('utf-8')
b'é»éç'
bytes(data,encoding='utf-8')
b'é»éç'服务器:
#服务器
from socket import *
import time
def main():
udpServerSocket = socket(AF_INET,SOCK_DGRAM)
#这里服务器可以绑定自己的ip地址和端口号,ip地址一般为空,表示本机的所有可用ip地址,
#可以是网络地址,本地地址和127.0.0.1
udpServerSocket.bind(("",12346))
BUFFERSIZE = 1024#单位字节
while True:
print("..waiting for message:")
data,addr = udpServerSocket.recvfrom(BUFFERSIZE)
print("[%s] %s received from %s"%(time.ctime(),data.decode('utf-8'),addr))
udpServerSocket.sendto(bytes("[%s] %s"%(time.ctime(),data.decode('utf-8')),encoding='utf-8'),addr)
if __name__ == "__main__":
main()客户端:
#客户端
from socket import *
udpClientSock = socket(AF_INET,SOCK_DGRAM)
#这里客户端可以绑定自己的ip地址和端口号,ip地址一般为空,表示本机的所有可用ip地址,
#可以是网络地址,本地地址和127.0.0.1。这样以后客户端的端口号就不变了。
#客户端一般不绑定端口
#udpClientSock.bind(('',9999))#不能这里绑网络地址,下面发送给本地地址。
BUFFERSIZE = 1024
while True:
data = input('>')
if not data:
break
udpClientSock.sendto(data.encode('utf-8'),("172.24.55.11",12346))
data,ADDR = udpClientSock.recvfrom(BUFFERSIZE)
if not data:
break
print(data.decode('utf-8'))
udpClientSock.close()udp模拟QQ聊天,多线程,两边同时接收,发送
#服务器
from threading import Thread
from socket import *
import time
BUFFERSIZE = 1024
#接收数据,打印
def receive_data():
global dest_addr
while True:
data,addr = udpSocket.recvfrom(BUFFERSIZE)
dest_addr = addr
print("\r>>[%s] receive %s from %s
<<"%(time.ctime(),data.decode('utf-8'),addr),end='')
def send_data():
while True:
data = input("<<")
udpSocket.sendto(data.encode('utf-8'),dest_addr)
udpSocket = None#一般空对象为None,空字符串为''
dest_addr = None
def main():
global udpSocket
udpSocket = socket(AF_INET,SOCK_DGRAM)
udpSocket.bind(('',45678))
receive_thread = Thread(target=receive_data)
send_thread = Thread(target=send_data)
receive_thread.start()
send_thread.start()
receive_thread.join()
send_thread.join()
if __name__ == '__main__':
main()
#客户端
from threading import Thread
from socket import *
import time
BUFFERSIZE = 1024
#接收数据,打印
def receive_data():
while True:
data,addr = udpSocket.recvfrom(BUFFERSIZE)
print("\r>>[%s] receive %s from %s
<<"%(time.ctime(),data.decode('utf-8'),addr),end='')
#发送数据
def send_data():
while True:
data = input("<<")
udpSocket.sendto(data.encode('utf-8'),('127.0.0.1',45678))
udpSocket = None#一般空对象为None,空字符串为''
def main():
global udpSocket
udpSocket = socket(AF_INET,SOCK_DGRAM)
udpSocket.bind(('', 45679))
receive_thread = Thread(target=receive_data)
send_thread = Thread(target=send_data)
receive_thread.start()
send_thread.start()
receive_thread.join()
send_thread.join()
if __name__ == '__main__':
main()
udpSocketClient.recvfrom(1024)报错问题:
参考:https://stackoverflow.com/questions/35805664/socket-recvfrom1024-throws-socket-error-invalid-argument-supplied#
data,addr = udpSocketClient.recvfrom(BUFFERSIZE)
OSError: [WinError 10022] 提供了一个无效的参数。在客户端接收数据之前,操作系统需要知道该进程的端口号,才能将数据发送给客户端。所以不能一上来就直接接收,需要先给客户端帮一个端口udpSocketClient.bind('ip',port)或者先让客户端发数据udpSocketClient.send(data,('destip',port)),这样客户端先发数据后,系统就会自动给客户端分配一个端口,这样客户端就能够接收数据了。
TCP没有广播,
import socket
import time
#这里的broadcast表示受限的广播地址,也可以直接写广播地址
# dest = ('',8080)
dest = ('172.24.54.255',8080)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#如果想要发送广播数据,需要对套接字进行设置,才能发送广播数据,否则不能发送广播数据
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
s.sendto("Hi".encode('utf-8'),dest)
print("等待对方回复")
while True:
data,address = s.recvfrom(2048)
print("[%s] received from %s:%s"%(time.ctime(),address,data.decode('utf-8'))) 下载:链接:https://pan.baidu.com/s/1OaJtyCIv1nJvMVcUhS-Cfw 密码:h6os
arp -a查看IP地址和Mac地址对应情况
arp -d清空本地缓存的IP地址和Mac地址对应信息
路由器配置:
配置主机IP地址,子网掩码,默认网关,配置路由器IP地址,子网掩码,静态路由,开启路由器端口。
A网段a和B网段b通信:
看a有没有默认网关,没有直接挂,
a通过arp解析网关的Mac地址
A将信息发给A的网关
A的网关将信息根据路由表发给下一跳路由器(不知道Mac地址的话,arp解析)
...
访问网页过程:
1.DNS域名解析
看主机PC7有没有设置默认网关,没有直接挂
如果不知道默认网关的Mac地址,就arp解析默认网关的Mac地址
主机PC7发送DNS请求解析数据给默认网关,网关转发给其他路由器,直到目的DNS服务器的默认网关,
DNS服务器的网关如果不知道DNS服务器的Mac地址,同样arp解析DNS服务器Mac地址
DNS网关将DNS请求解析数据发给DNS服务器
DNS服务器解析后,将数据返回给原主机PC7
2.主机PC和HTTP服务器TCP三次握手
3.http报文传输
4.tcp4次挥手。
TCP短连接:
每发送一次数据就要进行三次握手,四次挥手:TCP握手,发送数据,TCP四次挥手。。。TCP握手,发送数据,TCP四次挥手。应用:web应用,在HTTP/1.0中,默认使用的是短连接
TCP长连接:
建立一个连接后,只要没有显式关闭连接,就一直发送数据:TCP三次握手,发送数据,发送数据,TCP四次挥手。旨在建立 1 次 TCP 连接后进行多次请求和响应的交互。应用:看视频; HTTP/1.1起,默认使用长连接
备注:HTTP的长连接与短连接,本质上就是TCP的长连接与短连接。
TCP十种状态
常见网络攻击:
DoS(Denial of Service,拒绝服务)攻击
利用TCP三次握手漏洞,客户端在发送SYN,并且收到SYN+ACK后,迟迟不发送ACK,让服务器一直等待。例如,我一台电脑开十个进程,一个进程开十个线程攻击某个网站。占用它的listen队列,使其他人不能正常访问。
DNS服务器被劫持:
攻击DNS服务器,修改域名对应的ip,当用户访问某个网站时,跳转到其他的页面,例如广告,钓鱼网站。钓鱼网站先把别的网站例如淘宝的网页类容down下来,做一个和淘宝一模一样的界面,用户以为是真的淘宝,输入用户名,密码,信息就被获取了。
DNS服务器常常是重兵把守,
DNS欺骗:
用户在向DNS服务器请求域名解析的时候,攻击者⽤⼀个假的 DNS 应答来欺骗⽤户计算机,给它一个加的域名,IP对应。
Client的DNS查询请求和DNS Server的应答数据包是依靠DNS报文的ID标识来相互对应的。在进行域名解析时,Client首先用特定的ID号向DNS Server发送域名解析数据包,这个ID是随机产生的。DNS Server找到结果后使用此ID给Client发送应答数据包。Client接收到应答包后,将接收到的ID与请求包的ID对比,如果相同则说明接收到的数据包是自己所需要的,如果不同就丢弃此应答包。根据攻击者的查询和应答原理,可使用不同方法实现攻击,如:
(1)因为DNS Message仅使用一个简单的认证码来实施真实性验证,认证码是由Client程序产生并由DNS Server返回结果的,客户机只是使用这个认证码来辨别应答与申请查询是否匹配,这就使得针对ID认证码的攻击威胁成为可能。
arp攻击
攻击值攻击通信的双方,让他们的目的ip地址对应的Mac地址都是自己的,这样攻击者就可以接收到信息,接收到信息之后,为了不被发现,存储下来之后,再发送出去。
家里上网,就分配了一个公网ip地址,猫下面连路由器,路由器下面接电脑,手机。电脑,手机访问外网,通过了网络地址转换。
单进程服务器:(没啥实际应用)
服务器:
from socket import *
serverScoket = socket(AF_INET,SOCK_STREAM)
serverScoket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#让服务器意外结束时不能等待2MSL时间,就可以立即使用该端口
serverScoket.bind(("127.0.0.1",12345))
serverScoket.listen(5)
while True:
clientScoket,addr = serverScoket.accept()
print("serve for:",addr)
try:
while True:
data = clientScoket.recv(1024)
if len(data)>0:
print("receve %s from %s"%(data.decode('utf-8'),addr))
else:
print("%s客户端已关闭"%(addr))
break
except:
pass
finally:
clientScoket.close()
serverScoket.close()
客户端:
from socket import *
clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect(("127.0.0.1",12345))
while True:
data = input("please input the data:")
if len(data)>0:
clientSocket.send(data.encode('utf-8'))
else:
break
clientSocket.close()
同一时刻只能为一个用户服务,当服务器为一个客户服务时,而另外的新客户进行连接,只要服务器listen队列有空闲的位置,就会为这个新客户端进行连接,并且客户端可以发送数据,但当服务器为这个新客户端服务时,可能一次性把所有数据接收完毕。
多进程服务器:
服务器端:
from socket import *
from multiprocessing import *
#处理客户端的请求并为其服务
def dealWithClient(clientScoket,addr):
while True:
try:
data = clientScoket.recv(1024)
except:
print("%s客户端已关闭" % (str(addr)))#客户端直接X掉关闭
break
if len(data) > 0:
print("receve %s from %s" % (data.decode('utf-8'), addr))
else:
print("%s客户端已关闭" % (str(addr)))
break
clientScoket.close()
def main():
serverScoket = socket(AF_INET, SOCK_STREAM)
serverScoket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 让服务器意外结束时不能等待2MSL时间,就可以立即使用该端口
serverScoket.bind(("127.0.0.1", 12345))
serverScoket.listen(5)
try:
while True:
clientSocket,addr = serverScoket.accept()
# print(addr,type(addr))#add是一个元组
print("serve for %s"%(str(addr)))
client = Process(target=dealWithClient,args=(clientSocket,addr))
client.start()
#子进程已经copy了一份,这里可以关闭
clientSocket.close()
except:
pass
finally:
serverScoket.close()
if __name__ == '__main__':
main()多线程服务器:
服务器端
from socket import *
from threading import Thread
import time
#处理客户端的请求并为其服务
def dealWithClient(clientScoket,addr):
while True:
try:
data = clientScoket.recv(1024)
except:
print("%s客户端已关闭" % (str(addr)))
break
if len(data) > 0:
print("receve %s from %s" % (data.decode('utf-8'), addr))
else:
print("%s客户端已关闭" % (str(addr)))
break
clientScoket.close()
def main():
serverScoket = socket(AF_INET, SOCK_STREAM)
serverScoket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 让服务器意外结束时不能等待2MSL时间,就可以立即使用该端口
serverScoket.bind(("127.0.0.1", 12345))
serverScoket.listen(5)
try:
while True:
time.sleep(5)
clientSocket,addr = serverScoket.accept()
# print(addr,type(addr))#add是一个元组
print("serve for %s"%(str(addr)))
client = Thread(target=dealWithClient,args=(clientSocket,addr))
client.start()
#线程中共享这个套接字,这里不能关闭
# clientSocket.close()
except:
pass
finally:
serverScoket.close()
if __name__ == '__main__':
main()单进程服务器_非阻塞
from socket import *
clientSocketList = []
def main():
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind(('127.0.0.1',12345))
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.listen(5)
# 将套接字设置为非阻塞,这样就不会卡在accept处了
serverSocket.setblocking(False)
while True:
try:
clientSocket,addr = serverSocket.accept()
except :
pass
else:
print("一个新客户端到来:%s"%str(addr))
#将clientSocket设置为非阻塞,在recv处就不阻塞了
clientSocket.setblocking(False)
clientSocketList.append((clientSocket,addr))
for clientSocket,addr in clientSocketList:
try:
data = clientSocket.recv(1024)
except BlockingIOError:
pass
except ConnectionResetError:
clientSocket.close()
clientSocketList.remove((clientSocket, addr))
print("%s已经下线" % str(addr))
break
else:
if len(data)>0:
print("%s:%s"%(str(addr),data.decode('utf-8')))
else:
clientSocket.close()
clientSocketList.remove((clientSocket,addr))
print("%s已经下线"%str(addr))
if __name__ == '__main__':
main() | 留言与评论(共有 0 条评论) “” |