二十二、网络编程

简介: 网络编程的一些基本概念: 1.地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。  主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址。

网络编程的一些基本概念:

1.地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。

 主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址。
 收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
2 .tcp协议:TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
tcp 的链接有三次握手,断开有四次挥手,四次挥手的原因是因为tcp下一的半关闭原则。
3.udp协议:UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快
 

互联网协议与osi模型

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

每层运行常见物理设备

 

一.套接字(socket)初使用

基于TCP协议的socket

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

 

服务端  
import socket
s = socket.socket()   #买电话
id_port = ('127.0.0.1',8000) #买电话卡
s.bind(id_port)  #把电话装上电话卡
s.listen() #等待电话打进来 conn,adress = s.accept() #接受到了消息 msg = conn.recv(1024) #接受信息,接受的一点是字节类型 print(msg.decode()) # 打印,解码 inp = input('<<<<') #输入要发送的信息 new_msg = conn.send(inp.encode('utf-8)) # 把发送的信息编码,发送 s.close()

 

客户端
import socket
s = socket.socket()
id_port = ('127.0.0.1',8000)
s.connect(id_port)
msg = input('<<<')
s.send(msg.encode('utf-8')
new_msg = s.recv(1024)
print(new_msg.decode())
s.close()

 

基于UDP协议的socket

udp是无链接的,启动服务之后可以直接接受消息不需要提前建立链接

简单使用

服务端
import socket
udp_s = socket.socket(type = socket.SOCK_DGRAM)# 创建套接字
id_port = ('127.0.01',8000)   
udp_s.bind(id_port)                            #为套接字绑定ip
msg,addr = udp_s.recvfrom(1024)                 
print(msg.decode())
inp = input('<<<')
udp_s.sendto(inp.encode('utf-8),addr)          #这里发送消息给客户端要带上地址,
udp_s.close()

 

客户端
import socket
s = socket.socket(type = socket.SOCK_DRGAM)
id_port = ('127.0.0.1',8000)
msg = input('<<<')
s.sendto(msg.encode('utf-8'),idport)
msg,addr = s.recv(1024)
print(msg.decode('utf-8))
s.close()

 

 udp协议和tcp的差别:

服务端:tcp的服务端需要s.listen()这个过程   并且是conn,addr = s.accept()  后面的send 和recv 都是通过conn来进行,所以后面的发送不需要把addr加上。

              udp的服务端没有listen这个过程,直接是msg,addr  = s.recv(1024) 后面的是s.sendto(mag,addr)

客户端:tcp的客户端是id_port 与s绑定是s.connect(id_port)         s.send()       msgr = s.recv(1024)

              udp的客户端是不需要客户端与ip_port 绑定的的,直接发送的时候 s.sendto(msg,id_port)   msg,addr = s.recv(1024)

二、黏包问题

tcp协议的黏包成因详谈:

首先明确一点,黏包只发生在TCP协议,udp协议不会产生黏包,udp要么报错,要么发送丢失,也就是不完整。至于为什么我们稍后来谈。这里只搞清楚一点只有tcp会有黏包现象。
为什么tcp会有黏包:表面上看是由于发送方和接受方的缓存机制,也就是说的拆包,和tcp'协议是面向通信流(也就是那种byte流的形式)的特点,造成了这些情况,而真正的罪魁祸首其实是,接受端根本不知道要接受的数据怎么断句和接受数据的大小,所以才造成了坑爹的黏包现象。
深层次的分析:1.tcp协议在发送消息 如果消息的数量量大于的网卡的mtu值,就会把这个数据包拆包,分几次发送过去,这样就容易造成一次性接受消息不完整的情况,分几次接受,这是容易造成黏包的第一个原因。但是同时也是tcp可靠的点,只要没有发送完会一直发送。
       2.由于tcp协议面向流的通信特点和nagle算法。如果在发送两条间隔很短的消息且这样两条消息的长度特别短 ,这时候就要采用nagle算法,把这两条消息整合成一条消息打包发送。这时候接收端就无法合理的拆包。就造成消息混乱,也就是黏包。同时这也是tcp协议面向流通信的特点,这也是。
udp协议不产生黏包的原因:
主要是udp协议的通信是面向消息的,每次不管是接受还是发送都是接受一整条消息,不会去拆包,除非这个消息大于接受范围就会发送不完整,且下次也不会再继续发送,即使发送为,且每次发送消息都会自动带上端口号和ip地址,所以即使发送为空接收端也会收到消息。tcp协议如果发空消息,接收端会阻塞。
三、用struct解决黏包问题

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

发送时 接收时
先发送struct转换好的数据长度4字节 先接受4个字节使用struct转换成数字来获取要接收的数据长度
再发送数据 再按照长度接收数据
server端
#!user/bin/python3
#Author:Mr.Yuan
#-*- coding:utf-8 -*-
#@time: 2018/5/7 19:00
import socket
import os
import struct
import json
import time
id_port = ('127.0.0.1',9000)
s = socket.socket()
s.bind(id_port)
s.listen()
cnng,addr = s.accept()
dic = {'filename':r'H:\pycharm文件\a',
       'filesize':os.path.getsize(r'D:\feiq\Recv Files\python11期day35\video2.mp4')}
str_dic = json.dumps(dic).encode('utf-8')
struct_dic = struct.pack('i',len(str_dic))
cnng.send(struct_dic)
cnng.send(str_dic)
f = open(r'D:\feiq\Recv Files\python11期day35\video2.mp4','rb')
while dic['filesize']:
    content = f.read(1024)
    dic['filesize']-=len(content)
    print(dic['filesize'])
    cnng.sendall(content)
cnng.close()
s.close()

 

 
client端
#!user/bin/python3
#Author:Mr.Yuan
#-*- coding:utf-8 -*-
#@time: 2018/5/7 19:00
import socket
import json
import struct
id_port = ('127.0.0.1',9000)
s = socket.socket()
s.connect(id_port)
struct_message = s.recv(4)
dic_len = struct.unpack('i',struct_message)[0]
str_dic = json.loads(s.recv(dic_len).decode())
print(str_dic)
with open('H:\pycharm文件\mp6.mp4','wb') as f :
    while str_dic['filesize']:
        recv_content = s.recv(1024)
        str_dic['filesize'] -= len(recv_content)
        print(str_dic['filesize'])
        f.write(recv_content)
s.close()

 四、一个服务端连接多个客户端写法

#服务端
import socketserver
class MyServe(socketserver.BaseRequestHandler):
    def handle(self):#必须写这个函数名  最先执行这个方法
        self.request.sendall(bytes('欢迎致电10086...巴拉巴拉一大推',encoding='utf-8'))
        while True:
            date = self.request.recv(1024)
            print('%s:%s'% (self.client_address,date.decode()))
            self.request.sendall(bytes('我收到了',encoding='utf-8'))
if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8000),MyServe)
    server.serve_forever()    #让handle方法永远执行下去

 

#客户端
import  socket
ip_port = ('127.0.0.1',8000)
s = socket.socket()
s.connect(ip_port)
msg = s.recv(1024)
print(msg.decode())
while True:
    inp = input('<<<<')
    if len(inp)==0:continue
    s.send(bytes(inp,encoding='utf-8'))
    data = s.recv(1024)
    print(data.decode())

s.close()

 

 

目录
相关文章
|
6月前
|
存储 传感器 Linux
Linux应用开发基础知识——I2C应用编程(十二)
Linux应用开发基础知识——I2C应用编程(十二)
227 0
Linux应用开发基础知识——I2C应用编程(十二)
|
网络协议 安全 Java
Java网络编程基础知识详解
网络编程是现代软件开发中不可或缺的一部分,它使我们能够在不同的计算机之间实现数据传输和通信。Java作为一种强大的编程语言,提供了丰富的网络编程库,使开发者能够轻松地创建网络应用程序。本文将介绍Java网络编程的基础知识,面向初学者,详细讨论网络通信的概念、Socket编程、服务器和客户端编程等内容。
210 0
|
5月前
|
Java 数据挖掘 开发者
Java网络编程进阶:Socket通信的高级特性与应用
【6月更文挑战第21天】Java Socket通信是分布式应用的基础,涉及高级特性如多路复用(Selector)和零拷贝,提升效率与响应速度。结合NIO和AIO,适用于高并发场景如游戏服务器和实时数据分析。示例展示了基于NIO的多路复用服务器实现。随着技术发展,WebSockets、HTTP/2、QUIC等新协议正变革网络通信,掌握Socket高级特性为应对未来挑战准备。
49 1
|
1月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
|
3月前
|
缓存 网络协议 算法
网络编程原理
网络编程原理
|
4月前
|
Java
Socket网络编程基础教程
Socket网络编程基础教程
|
4月前
|
Java API 开发者
Java网络编程基础与Socket通信实战
Java网络编程基础与Socket通信实战
|
6月前
|
网络协议 Java API
Python网络编程基础(Socket编程)Twisted框架简介
【4月更文挑战第12天】在网络编程的实践中,除了使用基本的Socket API之外,还有许多高级的网络编程库可以帮助我们更高效地构建复杂和健壮的网络应用。这些库通常提供了异步IO、事件驱动、协议实现等高级功能,使得开发者能够专注于业务逻辑的实现,而不用过多关注底层的网络细节。
|
6月前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
网络协议
十四 网络编程
十四 网络编程
55 0