网络通信
前言
什么是TCP/IP、UDP
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
如下图,TCP和UDP写两者的关系图。
Socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
Socket在TCP和UDP协议的那块位置,如下图所示。
基于TCP协议的网络通信
基于TCP协议的网络通信,就类似于:一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。
基于TCP协议的网络通信,就如上图所示。先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
程序设计:
服务器端:
服务器程序要先与客户机程序启动,步骤以及调用函数:
1)调用socket()函数创建一个流式套接字,返回套接字号s
2)调用bind()将s绑定到已知地址,通常为本地ip
3)调用listen()将s设为监听模式,准备接收来自各客户端的连接请求
4)调用accept()等待接受客户端连接请求
5)如果接收到客户端请求,则accept()返回,得到新的套接字ns
6)调用rev()接收来自客户端的数据,调用send()向客户端发送数据
7)与客户端通信结束,服务器端可以调用shutdown()对方不再接收和发送数据,也可以由客户端程序断开连接,断开连接后,服务器进程调用closesocket()关闭套接字ns,此后服务器返回第四步
8)如果要退出服务器程序,则调用closesocket()关闭最初的套接字s
客户端:
客户端程序步骤以及调用函数:
1)调用WSAStartup()函数加载Windows Sockets动态库,然后调用socket()函数创建一个流式套接字,返回套接字号s。
2)调用connect()函数将套接字s连接到服务器
3)调用send()函数向服务器发送数据,调用recv()函数接收来自服务器的数据。
4)与服务器的通信结束后,客户端程序可以调用close()函数关闭套接字。
基于UDP协议的网络通信
如果Socket通信基于UDP,则数据传输前不需要连接,类似发短信或发电报,即使对方不在线,也可以发送数据,发送的数据在指定时间没有得到对方响应,则视为操作超时,可以选择超时后重新发送数据。
Python设计中的相关函数:
socket()函数
socket()函数用于创建与指定的服务提供者绑定套接字,函数原型如下:socket=socket.socket(familly,type)
参数说明如下:familly,指定协议的地址家族,可为AF_INET或AF_UNIX。
AF_INET家族包括Internet地址,AF_UNIX家族用于同一台机器上的进程间通信。
type,指定套接字的类型。
s=socket.socket() # 初始化一个TCP类型的Socket
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #初始化一个UDP类型的socket
bind()函数由服务器端调用
bind()函数可以将本地地址与一个Socket绑定在一起,函数原型如下:socket.bind( address ),参数address是一个双元素元组,格式是(host,port)。host代表主机,port代表端口号。
listen()函数
listen()函数可以将套接字设置为监听接入连接的状态,函数原型如下:
listen(backlog);参数backlog指定等待连接队列的最大连接数。默认是1,一般设置为5
accept()函数
在服务器端调用listen()函数监听接入连接后,可以调用accept()函数来等待接受连接请求。accept()的函数原型如下:connection, address = socket.accept()
调用accept()方法后,socket会进入waiting状态。客户请求连接时,accept()方法会建立连接并返回服务器。accept()方法返回一个含有两个元素的元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素 address是客户的Internet地址。
recv()函数 TCP接收数据
调用recv()函数可以从已连接的Socket中接收数据。recv()的函数原型如下:
buf = sock.recv(size)
参数sock是接收数据的socket对象,参数size指定接收数据的缓冲区的大小。recv()的函数的返回接收的数据。
send()函数 TCP发送数据
调用send()函数可以在已连接的Socket上发送数据。send()的函数原型如下:sock.recv(buf),参数sock是在已连接的Socket上发送数据。参数buf是也要已连接的Socket上发送数据。
close()函数
close ()函数用于关闭一个Socket,释放其所占用的所有资源。socket()的函数原型如下:s.closesocket();参数s表示要关闭的Socket。
Sendto(): 使用UDP发送数据使用
Recvfrom():UDP接收数据专用
sk.recvfrom(bufsize[.flag])
与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
sk.sendto(string[,flag],address)
将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。
基于TCP协议python的socket通信:
#服务器端 import socket s=socket.socket() # host=input("请输入IP:") s.bind((host,8888))# s.listen(5) while True: c,add=s.accept()#等待连接,c表示新的套接字,add表示连接的ip地址 while True: try: data = c.recv(1024) print(data.decode("utf-8")) str=input("请输入你要回复的消息") c.send(str.encode()) except Exception: break c.close() s.close() #客户端 import socket s=socket.socket() # host=input("请输入IP:") s.connect((host,8888)) while True: data = input('>>>请输入发送给服务器的消息').strip() s.send(data.encode('utf-8')) ret = s.recv(1024) print(ret.decode('utf-8'))
基于UDP协议的python程序设计
#服务器端 import socket s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # s.bind(("127.0.0.1",8888))# while True: while True: try: data,addr = s.recvfrom(1024) print(data.decode("utf-8")) str=input("请输入你要回复的消息") s.sendto(str.encode(),addr) except Exception: break s.close() #客户端 import socket s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # s.connect(("127.0.0.1",8888)) while True: data = input('>>>请输入发送给服务器的消息').strip() s.sendto(data.encode('utf-8'),('127.0.0.1',8888)) ret = s.recv(1024) print(ret.decode('utf-8'))
基于socket的其它应用
ip地址查询
import socket import time import requests from lxml import etree def ym_ip(url): ip_list=[] rs=socket.getaddrinfo(url,None) for i in rs: ip_list.append(i[4][0]) return ip_list print(ym_ip("www.scitc.com.cn")) print(ym_ip("www.baidu.com"))
CDN技术
#结合ip查询的函数 #实现CDN判断 def check_CDN(url): ip_list=ym_ip(url) if len(ip_list)>1: return "存在CDN" else: return "不存在CDN" print(check_CDN("www.scitc.com.cn")) print(check_CDN("www.baidu.com"))
子域名获取
def check_zym(url): # url www.scitc.com.cn url=url.replace("www",'') # url .scitc.com.cn f =open('dic.txt',encoding="utf-8") for i in f: i=i.replace('\n','') url_new=i+url #print(url_new) #socket.gethostbyname(url)方法中的url参数不能带有 #“http”这样的协议前缀,否则不能解析成IP地址。 try: ip=socket.gethostbyname(url_new) print(url_new,"--->",ip) time.sleep(0.1) except Exception: time.sleep(0.1) pass check_zym('www.cbyzsc.com')