socket套接字编程
套接字介绍
1. 套接字 : 实现网络编程进行数据传输的一种技术手段
2. Python实现套接字编程:import socket
3. 套接字分类
>流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案。(面向连接--tcp协议--可靠的--流式套接字)
>数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案。(无连接--udp协议--不可靠--数据报套接字)
tcp套接字编程
服务端流程
1 from socket import * 2 3 #创建流式套接字 4 sockfd = socket(AF_INET,SOCK_STREAM,0) 5 6 #绑定IP端口 7 sockfd.bind(('127.0.0.1',8888)) 8 9 #设置监听套接字,创建监听队列 10 sockfd.listen(5) 11 12 while True: 13 print("waiting for connect....") 14 #等待客户端链接 15 connfd,addr = sockfd.accept() 16 print("connect from",addr) 17 18 while True: 19 #收发消息 20 21 data = connfd.recv(1024) 22 23 if not data: 24 break 25 26 print(data.decode()) 27 28 #发消息 29 connfd.send('来,确认下眼神'.encode()) 30 #关闭套接字 31 connfd.close() 32 33 sockfd.close()TCP_server.py
1. 创建套接字
sockfd=socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0)
功能:创建套接字
参数: socket_family 网络地址类型 AF_INET表示ipv4
socket_type 套接字类型 SOCK_STREAM(流式) SOCK_DGRAM(数据报)
proto 通常为0 选择子协议
返回值: 套接字对象
2. 绑定地址
>本地地址 : 'localhost' , '127.0.0.1'
>网络地址 : '172.40.91.185'
>自动获取地址: '0.0.0.0'
sockfd.bind(addr)
功能: 绑定本机网络地址
参数: 二元元组 (ip,port) ('0.0.0.0',8888)
```
3. 设置监听
sockfd.listen(n)
功能 : 将套接字设置为监听套接字,确定监听队列大小
参数 : 监听队列大小
```
4. 等待处理客户端连接请求
connfd,addr = sockfd.accept()
功能: 阻塞等待处理客户端请求
返回值: connfd 客户端连接套接字
addr 连接的客户端地址
```
5. 消息收发
data = connfd.recv(buffersize)
功能 : 接受客户端消息
参数 :每次最多接收消息的大小
返回值: 接收到的内容
n = connfd.send(data)
功能 : 发送消息
参数 :要发送的内容 bytes格式
返回值: 发送的字节数
```
6. 关闭套接字
sockfd.close()
功能:关闭套接字
```
客户端流程
1 # 接受的客户端 2 3 4 from socket import * 5 6 #创建套接字 7 sockfd = socket(AF_INET,SOCK_STREAM) 8 9 #发起连接 10 sockfd.connect(('127.0.0.1',8888)) 11 12 while True: 13 msg = input("发消息>> ") 14 #发送消息 15 sockfd.send(msg.encode()) 16 if not msg: 17 break 18 19 #接收消息 20 data = sockfd.recv(1024) 21 print(data.decode()) 22 23 # msg = input("Msg>>") 24 # scorfd.send(msg.encode()) 25 26 # data = sockfd.recv(1024) 27 # print(data.decode()) 28 29 #关闭 30 sockfd.close()TCP_client.py
1. 创建套接字
>注意:只有相同类型的套接字才能进行通信
2. 请求连接
sockfd.connect(server_addr)
功能:连接服务器
参数:元组 服务器地址
3. 收发消息
>注意: 防止两端都阻塞,recv send要配合
4. 关闭套接字
tcp 套接字数据传输特点
>* tcp连接中当一端退出,另一端如果阻塞在recv,此时recv会立即返回一个空字串。
>* tcp连接中如果一端已经不存在,仍然试图通过send发送则会产生BrokenPipeError
>* 一个监听套接字可以同时连接多个客户端,也能够重复被连接
网络收发缓冲区
1. 网络缓冲区有效的协调了消息的收发速度
2. send和recv实际是向缓冲区发送接收消息,当缓冲区不为空recv就不会阻塞。
tcp粘包
socket.time.sleep(0.1)
>原因:tcp以字节流方式传输,没有消息边界。多次发送的消息被一次接收,此时就会形成粘包。
>影响:如果每次发送内容是一个独立的含义,需要接收端独立解析此时粘包会有影响。
>处理方法
>>1. 人为的添加消息边界
>>2. 控制发送速度
UDP套接字编程
服务端流程
1 from socket import * 2 import sys 3 from time import ctime 4 5 6 ADDR = ('127.0.0.1',8888) 7 BUFFERSIZE = 1024 8 9 #创建数据报套接字 10 sockfd = socket(AF_INET,SOCK_DGRAM) 11 #绑定地址 12 sockfd.bind(ADDR) 13 14 #收发消息 15 while True: 16 data,addr = sockfd.recvfrom(BUFFERSIZE) 17 print('recv from %s:%s'%(addr,data.decode())) 18 sockfd.sendto\ 19 (("[%s] 接收到消息"%ctime()).encode(),addr) 20 21 sockfd.close() 22 23 24 25 26 #服务端, udp 27 from socket import * 28 29 HOST = '127.0.0.1' 30 PORT = 9999 31 ADDR = (HOST, PORT) 32 #创建数据报套接字 33 sockfd = socket(AF_INET,SOCK_DGRAM) 34 #绑定地址 35 sockfd.bind(ADDR) 36 #收发消息 37 while True: 38 data,addr = sockfd.recvfrom(1024) 39 print('Receive from %s:%s' % (addr,data.decode())) 40 # sockfd.sendto(("[%s] 接收到消息"%ctime()).encode(),addr) 41 sockfd.sendto("收到消息".encode(), addr) 42 sockfd.close()UDP_server.py
1. 创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)
2. 绑定地址
sockfd.bind(addr)
3. 消息收发
data,addr = sockfd.recvfrom(buffersize)
功能: 接收UDP消息
参数: 每次最多接收多少字节
返回值: data 接收到的内容
addr 消息发送方地址
n = sockfd.sendto(data,addr)
功能: 发送UDP消息
参数: data 发送的内容 bytes格式
addr 目标地址
返回值:发送的字节数
4. 关闭套接字
sockfd.close()
客户端流程
1 from socket import * 2 import sys 3 4 #从命令行传入IP和端口 5 #python3 udp_server.py 172.60.50.42 8888 6 if len(sys.argv) < 3: 7 print(''' 8 argv is error!!! 9 input as 10 python3 udp_server.py 172.60.50.42 4260 11 ''') 12 13 HOST = sys.argv[1] 14 PORT = int(sys.argv[2]) 15 ADDR = (HOST,PORT) 16 BUFFERSIZE = 1024 17 18 #创建数据报套接字 19 sockfd = socket(AF_INET,SOCK_DGRAM) 20 21 while True: 22 data = input("消息>>") 23 #直接回车退出 24 if not data: 25 break 26 sockfd.sendto(data.encode(),ADDR) 27 data,addr = sockfd.recvfrom(BUFFERSIZE) 28 print('从服务器收到:',data.decode()) 29 sockfd.close() 30 31 32 #客户端 33 from socket import * 34 import sys 35 36 #命令行输入服务器地址 37 if len(sys.argv) < 3: 38 print('''argv is error !! 39 start as 40 python3 udp_client.py 127.0.0.1 8888 41 ''') 42 # raise 43 44 HOST = sys.argv[1] 45 PORT = int(sys.argv[2])#字符串转int类型 46 ADDR = (HOST,PORT) 47 48 #创建数据报套接字 49 sockfd = socket(AF_INET, SOCK_DGRAM) 50 51 while True: 52 data = input("消息: ") 53 if not data: 54 break 55 sockfd.sendto(data.encode(),ADDR) 56 data,addr = sockfd.recvfrom(1024) 57 print("从服务端收到: ", data.decode()) 58 59 sockfd.close() 60 61 # $ python3 udp_client.py 127.0.0.1 8888 62 #要加ip名和端口名才能运行UDP_client.py
1. 创建套接字
2. 收发消息
3. 关闭套接字
---------------
>总结 :tcp套接字和udp套接字编程区别
>>1. 流式套接字是以字节流方式传输数据,数据报套接字以数据报形式传输
>>2. tcp套接字会有粘包,udp套接字有消息边界不会粘包
>>3. tcp套接字保证消息的完整性,udp套接字则不能
>>4. tcp套接字依赖listen accept建立连接才能收发消息,udp套接字则不需要
>>5. tcp套接字使用send,recv收发消息,udp套接字使用sendto,recvfrom
---------------------
socket套接字属性
【1】 sockfd.type 套接字类型
【2】 sockfd.family 套接字地址类型
【3】 sockfd.getsockname() 获取套接字绑定地址
【4】 sockfd.fileno() 获取套接字的文件描述符
【5】 sockfd.getpeername() 获取连接套接字客户端地址
【6】 sockfd.setsockopt(level,option,value)
功能:设置套接字选项
参数: level 选项类别 SOL_SOCKET
option 具体选项内容
value 选项值
【7】 sockfd.getsockopt(level,option)
功能 : 获取套接字选项值
UDP套接字广播
1 #广播接收端 与udp的 2 3 from socket import * 4 5 HOST = '' 6 PORT = 8880 7 8 #创建数据报套接字 9 s = socket(AF_INET,SOCK_DGRAM)#加默认参数0变成流式套接字SOCK_STREAM 10 #固定接收端的端口号 11 s.bind((HOST,PORT)) 12 #设置套接字可以接收广播, 有此后变成与udp不同 13 s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)#broadcast 14 #设置套接字保护端口号 15 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#reuseaddr 16 17 18 # while True: 19 # try: 20 # message,addr = s.recvfrom(1024) 21 # print("从{}获取信息{}:".\ 22 # format(addr,message.decode()))#decode将“字节流”按照某种规则转换成'文本' str变unicode 23 # s.sendto(b"I am here",addr) 24 # except (KeyboardInterrupt,SyntaxError):#从终端ctrl+c的错 25 # raise 26 # except Exception as e: 27 # print(e) 28 29 # s.close() 30 31 while True: 32 try: 33 message,addr = s.recvfrom(1024) 34 print("获取信息: {}".\ 35 format(message.decode()))#decode将“字节流”按照某种规则转换成'文本' str变unicode 36 s.sendto(b"I am here",addr) 37 except (KeyboardInterrupt,SyntaxError):#从终端ctrl+c的错 38 raise#raise 引发一个异常 39 except Exception as e:#异常类 40 print(e) 41 42 s.close()broadcast_recv.py
1 # 发送端 2 3 from socket import * 4 from time import sleep 5 6 #发送广播的地址 7 #<broadcast> 8 dest = ('176.122.14.255',8880)#端口号9999一致 9 #创建数据报套接字 10 s = socket(AF_INET,SOCK_DGRAM)#dgram 11 #设置能够发送广播 12 s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)#broadcast 13 14 while True: 15 sleep(2) 16 s.sendto("什么鬼啊aaaaaa啦啦啦啦啦啦啦".encode(),dest)#目标地址 17 data,addr = s.recvfrom(1024) 18 print("Received from %s:%s"%(addr,data.decode())) 19 s.close() 20 21 # while True: 22 # data = input('input: ') 23 # s.sendto(("@鸿182:"+ data).encode(),dest) 24 # s.close() 25 # 局域网聊天室,同端口号broadcast_send.py
* 广播定义 : 一端发送多点接收
* 广播地址 : 每个网络的最大地址为发送广播的地址,向该地址发送,则网段内所有主机都能接收。
TCP套接字之HTTP传输
HTTP协议 (超文本传输协议)
1. 用途 : 网页获取,数据的传输
2. 特点
应用层协议,传输层使用tcp传输
简单,灵活,很多语言都有HTTP专门接口
无状态,协议不记录传输内容
http1.1 支持持久连接,丰富了请求类型
3. 网页请求过程
1.客户端(浏览器)通过tcp传输,发送http请求给服务端
2.服务端接收到http请求后进行解析
3.服务端处理请求内容,组织响应内容
4.服务端将响应内容以http响应格式发送给浏览器
5.浏览器接收到响应内容,解析展示
HTTP请求(request)
1 #静态网页处理器 2 #采用循环的模式,无法满足客户端长连接 3 4 from socket import *#网络连接端点,导入模块 5 6 #处理客户端请求, 交互 7 def handleClient(connfd):#请求,调用函数 8 request = connfd.recv(2048)#请求套接字接受文件 9 # print('**************') 10 # print(request) 11 # print('**************') 12 #按照行切割请求, 方便查看 13 request_lines = request.splitlines() 14 for line in request_lines: 15 print(line.decode())#对分割后的文件解码 16 17 try: 18 f = open("index.html") 19 except IOError:#找不到页面, 文件出错 20 response = "HTTP/1.1 303 not Found\r\n"#http响应行 21 response += '\r\n'#无响应头, 有空行 22 response += '''====sorry ,file not find 23 ******************************* 24 Sorry bing i love you miss you. 25 ******************************* 26 ''' 27 else:#正常情况运行 28 response = "HTTP/1.1 200 OK\r\n"#成功响应头, 响应体是页面 29 response += '\r\n' 30 response += f.read()#响应体是页面 31 # for i in f: 32 # response += i 33 finally: 34 connfd.send(response.encode())#发送给浏览器 35 connfd.close() 36 37 #流程控制 38 def main(): 39 sockfd = socket()#创建流式套接字 40 sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#设置端口重用 41 sockfd.bind(('0.0.0.0',8888))#绑定套接字 42 sockfd.listen(10)#监听套接字 43 while True:#循环监听等待连接 44 print("Listen the port 8000..") 45 connfd,addr = sockfd.accept()#创建另一个套接字连接请求,便于接收一个后再接收, 46 #处理浏览器发来的请求 47 handleClient(connfd)#跟客户顿交互 48 connfd.close()#关闭套接字 49 50 51 if __name__ == "__main__":#调用主函数 52 main() 53 54 55 # --------------------------------------------------------------- 56 57 58 # #接收请求 59 # #查看请求 60 # #返回客户端请求 61 62 # def handleClient(): 63 # pass 64 65 66 # #创建tcp套接字, 调用handleClient完成功能 67 # def main(): 68 # pass 69 70 # if __name__=="__main__": 71 # main()HTTP_server.py
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>欢迎进入Alan主页</title> 6 </head> 7 <body> 8 <h1>Alan songzihong welcome to you </h1> 9 <h1>what is you name</h1> 10 <h1>How can i do cna help you </h1> 11 </body> 12 </html> 13 14 <!-- 没保存会只显示文件名 --> 15 <!-- html:5 + tab --> 16 <!-- h1 + tab -->index.html
* 请求行 : 具体的请求类别和请求内容
```
GET / HTTP/1.1
请求类别 请求内容 协议版本
```
请求类别:每个请求类别表示要做不同的事情
```
GET : 获取网络资源
POST :提交一定的信息,得到反馈
HEAD : 只获取网络资源的响应头
PUT : 更新服务器资源
DELETE : 删除服务器资源
CONNECT
TRACE : 测试
OPTIONS : 获取服务器性能信息
```
* 请求头:对请求的进一步解释和描述
```
Accept-Encoding: gzip
```
* 空行
* 请求体: 请求参数或者提交内容
http响应(response)
1. 响应格式:响应行,响应头,空行,响应体
* 响应行 : 反馈基本的响应情况
```
HTTP/1.1 200 OK
版本信息 响应码 附加信息
```
响应码 :
```
1xx 提示信息,表示请求被接收
2xx 响应成功
3xx 响应需要进一步操作,重定向
4xx 客户端错误
5xx 服务器错误
```
* 响应头:对响应内容的描述
```
Content-Type: text/html
```
* 响应体:响应的主体内容信息