计算机通讯
- mac地址(Media Access Control Address),也称为局域网地址(LAN Address),表示网络设备所在地址,用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。因为mac比较复杂,所以一般会使用IP来进行定位
- 通过网线或局域网进行数据传输。
TCP/IP
一个协议族,包含众多网络传输协议,如UDP、TCP、TCP、IP、FTP、SMTP众多协议,因为TCP、IP协议具有代表性,所以取名TCP/IP。其中协议又分为、应用层、传输层、网络层、数据链路层。
链路层
- 将数据处理成数据帧用于传输
网络层
- IP协议和IP地址
- Internet Protocol 网际互连协议,是[TCP/IP](https://baike.baidu.com/item/TCP%2FIP/214077)体系中的网络层协议
- Internet Protocol Address 互联网协议地址,由32位2进制组成,对服务器地址进行定位,有IPv4 和 IPv6版本,现在普遍使用IPv4,地址即将用尽。
传输层
主要作用是定义端口号,确定哪个端口发送数据,哪个端口接收数据。
UDP协议:从一个端口发送到另一个端口,但是不管数据对方有没有接收到
TCP协议:再UDP协议的基础上保证数据会被正确接收,其中过程有三次握手、四次挥手
- 三次握手
- 客户端—>服务段 询问是否可以链接
- 服务段—>客户端 回应可以链接
- 客户端—>服务段 链接服务端
- 四次挥手
- 客户端—>服务段 通知退出链接
- 服务段—>客户端 接收退出链接
- 客户端—>服务段 退出链接
- 服务段—>客户端 退出链接
- 三次握手
应用层
- 常见的有http,ftp,smtp等,在请求Header中,分别定义了请求数据格式Accept和响应数据格式Content-Type,有了这个规范以后,当对方接收到请求以后就知道该用什么格式来解析
- 服务端:对请求进行处理,按照请求方要求的格式将数据发送
- 客户端:收到响应后,按照规定的格式进行解读
Python实现UDP
- 套接字相当于想要给别人打电话,首先需要一部手机,信息想要传递,就得使用套接字。浏览器即使用套接字进行信息传输。
使用threading多线程,可以让服务器实现多任务
创建套接字
- socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
- family=socket.AF_INET IPv4 网络协议的套接字类型
- type=socket.SOCK_DGRAM 使用UDP传输协议
- 绑定ip和端口
- socket.bind((“ip地址”, 10099))
- 接收数据
- socket.recv() 返回数据,进制流形式
- socket.recvfrom() 返回数据,地址,元组形式
- 发送数据
- socket.sendto(data=””, address=””)
- 注意这里传参的时候不用写形参
- data为进制流格式,同时中文编码utf-8乱码,需要用gbk编码 ```python import socket import threading
- socket.sendto(data=””, address=””)
class ServerUDP(threading.Thread): def init(self):
# 基础初始化
super().__init__()
# 创建套接字
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 绑定本地端口
self.socket.bind(("localhost", 10099))
def __exit__(self, exc_type, exc_val, exc_tb):
# 关闭套接字
self.socket.close()
def run(self):
while True:
# 接收数据
data, addr = self.socket.recvfrom(1024)
data = data.decode('gbk')
print(f"你说: {data} 地址:{addr}")
if data == "退出":
return
class ClientUDP(threading.Thread): def init(self):
# 基础初始化
super().__init__()
# 创建套接字
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 绑定本地端口
# self.socket.bind(("localhost", 8888))
def __exit__(self, exc_type, exc_val, exc_tb):
# 关闭套接字
self.socket.close()
def run(self):
while True:
# 发送数据
data = input("输入信息:")
self.socket.sendto(data.encode("gbk"), ("localhost", 10099))
if data == "退出":
return
if name == ‘main‘: s = ServerUDP() s.start()
c = ClientUDP()
c.start()
<a name="QAHL3"></a>
#### TCP服务端
- socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)<br />
- 绑定本地端口
- self.socket.bind(("localhost", 10099))
- 监听连接,最大挂起128个连接,再多了就会拒绝
- socket.listen(128)
- 接收新的套接字
- sock, addr = self.socket.accept()
- sock 新的套接字
- addr 发送信息的地址
- 使用新的套接字来收发信息
```python
import threading
import socket
class ServerTCP(object):
def __init__(self):
# 基础初始化
super().__init__()
# 创建套接字
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 绑定本地端口
self.socket.bind(("localhost", 10099))
# 监听
self.socket.listen(128)
def __exit__(self, exc_type, exc_val, exc_tb):
# 关闭套接字
self.socket.close()
def run(self):
print("服务端已开启")
while True:
# 接受新的套接字 阻塞
sock, addr = self.socket.accept()
print(addr, "已连接")
# 遇到新的连接创建新的线程接收数据
t = threading.Thread(target=self.recieve_data, args=(sock, addr))
t.start()
def recieve_data(self, sock, addr):
while True:
# 接收数据
data = sock.recv(1024)
data = data.decode('gbk')
print(f"地址{addr}: {data} ")
if __name__ == '__main__':
s = ServerTCP()
s.run()
TCP客户端
import socket
import threading
class ClientTCP(object):
def __init__(self):
# 基础初始化
super().__init__()
# 创建套接字
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 绑定本地端口
self.socket.bind(("localhost", 10098))
def __exit__(self, exc_type, exc_val, exc_tb):
# 关闭套接字
self.socket.close()
def run(self):
# 连接服务端
self.socket.connect(("localhost", 10090))
while True:
# 发送数据
data = input("输入信息:")
# 接受数据
self.socket.send(data.encode("gbk"))
print(self.socket.recv(1024))
if data == "退出":
return
if __name__ == '__main__':
c = ClientTCP()
c.run()