1.端口
2**16 = 65536个 [0,65535)
动态端口 1024-65535
查看端口 netstat - an
2.ip地址
ip地址包括两部分:网络地址和主机地址
ipv4
如果是C类 0 和255 不肯用(最大和最小)
0表示 网络号 例如:192.168.119.0四
255表示 广播地址192.168.119.255
2^10→K 2^20→M 2^30→G ipv4 2^32→4G
3.socket SSS重要
进程间的通信 socket 套接字(插口)
tcp通信:慢 稳定 打电话 传输控制协议
udp通信:快 不稳定(丢数据)写信 用户数据包协议
from socket import *
s = socket(AF_INET,SOCK_DGRAM)
s.sendto("内容",("ip",8080))
---------------接收数据↓---
from socket import *
#创建套接字
s = socket(AF_INET,SOCK_DGRAM)
# 绑定本地的相关信息,如果不绑定,系统会随机分配
s.bind(("",7788))
s.sendto(b"haha",("ip",8080))
# 等待接收对方发送的数据
recvData = s.recvfrom(1024) # 1024表示本次接收最大字节
print(recvData)
# 关闭套接字
s.close()
单工 半双工 全双工
python3 环境编写
from socket import *
udpSocket = socket(AF_INET, SOCK_DGRAM)
destIp = input("请输入目的ip:")
destPort = int(input("请输入目的port:"))
sendData = input("请输入要发送的数据:")
#udpSocket.sendto(sendData.encode("utf-8"), (destIp, destPort))
udpSocket.sendto(sendData.encode("gb2312"), (destIp, destPort))
接收数据
from socket import *
udpSocket = socket(AF_INET, SOCK_DGRAM)
udpSocket.bind(("", 7789))
recvData = udpSocket.recvfrom(1024)
content, destInfo = recvData
print("content is %s"%content)
print("content is %s"%content.decode("gb2312"))
4.网络通信过程
5.聊天室的创建
6.模拟QQ聊天
from threading import Thread
from socket import *
# 接收数据
def recvData():
while True:
recvInfo = udp_s.recvfrom(1024)
print("r>>%s:%s" % (recvInfo[1],recvInfo[0].decode("gb2312")))
# 发送数据
def sendData():
while True:
sendInfo = input("r<<")
udp_s.sendto(sendInfo.encode("gb2312"),(destIp,destPort))
udp_s = None
destIp = ""
destPort = 0
def main():
global udp_s
global destIp
global destPort
destIp = input("请输入ip:")
destPort = int(input("请输入端口:"))
udp_s = socket(AF_INET,SOCK_DGRAM)
udp_s.bind(("",8888))
tr = Thread(target=recvData)
ts = Thread(target=sendData)
tr.start()
ts.start()
tr.join()
ts.join()
if __name__ == '__main__':
main()
7.wireshark和tftp安装
tftp是服务器
8.tftp服务器 自己编写客户端 下载服务器中的文件(未完待续)
8.udp广播
单播 多播 广播
广播:
from socket import *
dest = ("<broadcast>",7788)
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
s.sendto(b"haha",dest)
9.总结
UDP(用户数据包协议):
TCP(传输控制协议):
socket的套接字 是主动套接字
listen()将主动套接字变为被动
TCP服务器编写:
from socket import *
s = socket(AF_INET,SOCK_STREAM)
s.bind(('',7788))
s.listen(5)
# newSocket表示新的套接字(为这个客户端服务,s就可以等待其他客户端连接)
# sInfo表示新套接字的ip及port
newSocket,sInfo = s.accept()
recvData = newSocket.recv(1024)
print("%s:%s" % (str(sInfo),recvData.decode("gb2312")))
newSocket.close()
s.close()
服务器:
from socket import *
from multiprocessing import Process
def dealDatas():
while True:
recvData = newSocket.recv(1024)
print("r>>%s" % recvData.decode("utf-8"))
sendInfo = input("<<")
if len(sendInfo)>0:
sendData = newSocket.send(sendInfo.encode("utf-8"))
else:
break
s = socket(AF_INET,SOCK_STREAM)
s.bind(('',7788))
s.listen(5)
while True:
newSocket,sInfo = s.accept()
p = Process(target=dealDatas)
p.start()
newSocket.close()
s.close()
客户端:
from socket import *
s = socket(AF_INET,SOCK_STREAM)
s.connect(("192.168.58.1",7788))
while True:
sInfo = input("r>>")
if len(sInfo) > 0:
s.send(sInfo.encode("utf-8"))
else:
break
recvData = s.recv(1024)
print("%s" % recvData)
s.close()
10.Cisco Packet Tracer
OSI 七层模型
ping命令 icmp协议 之后通过ARP协议获取MAC地址
ARP 根据IP 找MAC地址 RARP根据MAC地址找IP
链路层 接收MAC地址 1.广播MAC地址 2.电脑网卡物理IP地址
三台路由器连接连个不同网段的网络时
ip地址标记逻辑地址
mac地址标记实际地址
netmask 掩码和ip地址一起确认网络号 (通过按位与)
默认网关:发送的ip不在同一个网段内,会把这个ip转发给默认网关
两个设备之间的通信 写的是mac地址 IP地址不变
面试题!!!!
访问百度时过程:若果是第一次的话,先确认网关,有网关确认网关MAC地址(APR),域名访问三次握手,客户端给服务器发送请求数据,之后对方将数据传输。
第一步:如果以域名访问,先解析出 http://baidu.com的ip地址
(1) ARP获取默认网关MAC地址
(2)之后组织数据发送给默认网关(ip是DNS服务器ip,MAC地址是默认网关的MAC地址)
(3)默认网关拥有转发数据的能力,把数据转发给路由器
(4)路由器根据自己的路由协议,来选择一个合适的较快的路径 转发数据给目的网关
(5)目的网关(DNS服务器所在地网关),把数据转发给DNS服务器
(6)DNS服务器查询解析出http://baidu.com对应IP地址,并把他原路返回给请求域名的client
第二步:
(1)得到http://baidu.com 对应的IP地址,发送tcp三次握手,进行连接
(2)使用http协议发送请求给web
(3)web服务器收到数据请求后,查询得到结果,原路返回给浏览器
(4)浏览器接收数据 通过自己的渲染功能显示网页
(5)浏览器关闭tcp连接 即第四次挥手,
DHCP 自动分配ip地址协议
11.TCP与UDP对比
seq是数据包本身的序列号;ack是期望对方继续发送的那个数据包的序列号。
(面试题)为什么是三次握手 而不是两次!
主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
11.
12.常见的网络攻击
DOS攻击
DNS攻击
ARP攻击
python 使用原始套接字
13.NAT网络地址转换器
14.多进程服务器 和多线程服务器
多进程服务器 需要在try下面关闭 新客户端套接字,多线程不关闭(因为线程共用)
多进程:
from socket import *
from multiprocessing import Process
def dealWithClient(newSocket,newAdress):
while True:
recvData = newSocket.recv(1024)
if len(recvData)>0:
print("%s:%s" % (str(newAdress),recvData))
else:
print("%s已关闭" % newAdress)
break
newSocket.close
def main():
s = socket(AF_INET,SOCK_STREAM)
s.bind(("",7788))
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.listen(5)
try:
while True:
newSocket,newAdress = s.accept()
p1 = Process(target=dealWithClient,args={newSocket,newAdress})
p1.start()
newSocket.close()
finally:
s.close()
if __name__ == '__main__':
main()
多线程:
from socket import *
from threading import Thread
def dealWithData(newSocket,newAdress):
while True:
recvData = newSocket.recv(1024)
if len(recvData)>0:
print("%s:%s" % (str(newAdress),recvData))
else:
print("%s 断开" % newAdress)
break
newSocket.close
def main():
s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(("", 5555))
s.listen(5)
try:
while True:
newSocket, newAdress = s.accept()
t1 = Thread(target=dealWithData, args=(newSocket, newAdress))
t1.start()
finally:
s.close()
if __name__ == '__main__':
main()
单进程非阻塞服务器: !!!!!思想重要
from socket import *
s = socket(AF_INET,SOCK_STREAM)
s.setblocking(False)
s.bind(("",7788))
s.listen(10)
clientList = []
while True:
try:
newSocket,clientAdress = s.accept()
except:
pass
else:
print("新的客户端到来:%s" % str(clientAdress))
newSocket.setblocking(False)
clientList.append((newSocket,clientAdress))
for clientsocket,clientAdr in clientList:
try:
recvData = clientsocket.recv(1024)
except:
pass
else:
if len(recvData) > 0:
print("%s:%s" % (str(clientAdr),recvData))
else:
clientsocket.close()
clientList.remove((clientsocket,clientAdr))
print("%s已退出" % str(clientAdr))
select版服务器:(上限1024) → 轮询
poll:无上限 (与select相同)→ 轮询(慢)
epoll:无上限 → 事件通知机制
select版服务器
from socket import *
import select
server = socket(AF_INET,SOCK_STREAM)
server.bind(("",8888))
server.listen(5)
socketlist = [server]
while True:
readable,writeable,excptional = select.select(socketlist,[],[])
for socket in readable:
if socket == server:
clientSocket,clientAddress = socket.accept()
socketlist.append(clientSocket)
else:
recvData = socket.recv(1024)
if recvData:
socket.send(recvData)
print("%s:%s" % (str(clientAddress),recvData))
else:
socketlist.remove(socket)
socket.close()
epoll版服务器:
from socket import *
import select
s = socket(AF_INET,SOCK_STREAM)
s.bind(("",7777))
s.listen(5)
epoll = select.epoll()
epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET)
connections = {}
addresses = {}
while True:
epoll_list = epoll.poll()
for fd,event in epoll_list:
if fd == s.fileno():
client,addr = s.accept()
connections[client.fileno()] = client
addresses[client.fileno()] = addr
# select.EPOLLIN判断事件是否接收数据的事件
epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET)
elif fd == select.EPOLLIN:
recvData = connections[fd].recv(1024)
try:
if recvData:
print("%s:%s" % (str(addresses[fd]),recvData))
except:
pass
else:
epoll.unregister(fd)
connections[fd].close()
计算密集型 (例如or嵌套for很多) → 占用大量CPU → 多进程
IO密集型 →需要网络工能,大量时间都在等待网络数据到来 → 多线程 协程
协程的 实现方法:生成器(yeild)
协程 greenlet版(安装greenlet) 还有一种方法yelid +next
from greenlet import greenlet
import time
def test1():
while True:
print("a")
g2.switch()
time.sleep(0.5)
def test2()
while True:
print("b")
g1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
g1.switch
协程方法3 gevent (安装)
当gevent 遇到耗时操作时 切换执行 → gevent.sleep(1)
如果不耗时则往下执行
import gevent
def f(n):
for i in range(n)
print(gevent.getcurrent(),i)
gevent
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevert.spawn(f,5)
g1.join()
g2.join()
g3.join()
gevent版服务器
import gevent
from gevent import socket,monkey
monkey.patch_all()
def dealData(client,addr):
while True:
try:
recvData = client.recv(1024)
except:
pass
else:
if recvData:
print("%s:%s" %(str(addr),recvData))
else:
client.close()
s = socket.socket()
s.bind(("",6666))
s.listen(5)
while True:
cilent,addr = s.accept()
gevent.spawn(dealData,cilent,addr)