Python socket编程
1、IP地址简介
目的:用来标记网络上的一台电脑
windows和Linux查看网卡信息
Linux中 ifconfig
windows中 ipconfig
IP地址的分类
端口
端口分类
1.1 知名端口(well known ports)
80端口分配给HTTP服务
21端口分配给FTP服务
知名端口的范围是从0到1023
1.2 动态端口
动态端口的范围是从1024-65535
2、socket简介
2.1 TCP/IP协议
TCP/IP协议是Transmission Control Protocol/Internet Protocol的简写,即传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。
TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
TCP/IP协议
TCP/IP网络模型四层模型从根本上和OSI七层网络模型是一样的,只是合并了几层
2.2 socket
socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。白话说,socket就是两个节点为了互相通信,而在各自家里装的一部’电话’。
2.2.1 socket的使用
1.创建套接字ipv4(socket.AF_INET),udp套接字(socket.SOCK_DGRAM )
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
2.使用套接字收/发数据
udp_socket.sendto(send_data.encode(‘gbk’),(ipaddr,8888))
3.关闭套接字
udp_socket.close()
2.3 udp发送与接收程序
2.3.1 udp发送数据
#创建套接字
#family = AF_INET, 协议族 AF_INET ipv4
#套接字类型 type = UDP(数据报套接字 SOCK_DGRAM)、TCP(流式套接字 SOCK_STREAM)
#AF_INET = 2
#AF_INET6 = 23
import socket
def main():
#创建一个udp套接字
# ipaddr = '192.168.2.119'
# ipaddr = '127.0.0.1'
ipaddr = 'localhost'
send_data = 'python'
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_socket.sendto(send_data.encode('gbk'),(ipaddr,8888))
udp_socket.close()
if __name__ == '__main__':
main()
接收数据测试工具:NetAssist.exe
使用while循环,时刻处于数据发送状态
1 创建套接字
2 发送数据
3 关闭套接字
def main():
#1、创建一个udp套接字
ipaddr = '192.168.2.119'
# ipaddr = '127.0.0.1'
# ipaddr = 'localhost'
# send_data = '123'
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#""默认代表本机ip
bind_str = ("",8080)
udp_socket.bind(bind_str)
#发送数据
while True:
send_data = input('请输入发送内容:')
if send_data == 'exit' or send_data == 'quit':
break
udp_socket.sendto(send_data.encode('gbk'),(ipaddr,8888))
udp_socket.close()
if __name__ == '__main__':
main()
2.3.2 udp接收数据
1 创建套接字
2 绑定本地信息(IP和端口)
3 接收数据
4 打印数据
5 关闭套接字
import socket
def main():
#1、创建socket套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#2、绑定本地信息 bind_addr的 "" 表示绑定本机任意ip
bind_addr = ("",7789)
udp_socket.bind(bind_addr)
#3、接收数据,1024 表示本次接收的最大字节数
recv_data = udp_socket.recvfrom(1024)
#以元组形式接收信息:数据 (发送方的ip,端口号)
#(b'juran', ('192.168.2.119', 8888))
#4、打印套接字
print(recv_data)
#5、关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
用 while True 循环持续接收数据
import socket
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#bind_addr的 "" 表示绑定本机任意ip
bind_addr = ("",7789)
udp_socket.bind(bind_addr)
while True:
#1024 表示本次接收的最大字节数
recv_data = udp_socket.recvfrom(1024)
#元组 接收到的数据 (发送方的ip,端口号)
#(b'juran', ('192.168.2.119', 8888))
recv_addr = recv_data[1]
recvdata = recv_data[0]
print('%s:%s'%((str(recv_addr)),(recvdata.decode('gbk'))))
# print(recv_data)
udp_socket.close()
if __name__ == '__main__':
main()
端口绑定问题
如果程序运行时,没有绑定端口,那么操作系统会自动分配一个端口给程序。 而且同一端口,不能用两次。
2.4 udp聊天器
1.创建套接字 套接字是可以同时收发数据的
2.发送数据
3.接收数据
#定义发送数据函数
def send_data(udp_socket):
ipaddr = '192.168.2.119'
senddata = input('请输入发送内容:')
udp_socket.sendto(senddata.encode('gbk'),(ipaddr,8888))
#定义接收数据的函数
def recv_data(udp_socket):
recv_data = udp_socket.recvfrom(1024)
print('%s:%s'%(recv_data[1], recv_data[0].decode('gbk')))
import socket
def main():
#创建UDP套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#绑定本地信息(IP和端口)
udp_socket.bind(("",8888))
while True:
#发送数据
send_data(udp_socket)
#接收数据
recv_data(udp_socket)
#关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
3、TCP
介绍
- TCP协议,传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议
- TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
- TCP通信模型中,在通信开始之前,一定要先建立相关连接,才能收发数据。
3.1TCP特点
- 面向连接
- 通信双方必须先建立连接才能进行数据的传输
- 可靠传输
- TCP采用发送应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
3.2 TCP与UDP区别总结
1、TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
UDP通信
TCP通信
TCP服务器端:就是提供服务的一方
而客户端,就是需要被服务的一方
3.3 TCP客户端构建流程
1.创建socket
2.链接服务器
3.接收数据(最大接收2014个字节)
4.关闭套接字
import socket
def main():
# 创建 TCP 套接字
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#建立连接,服务器ip 和 服务器端口
tcp_addr = ('192.168.2.119')
tcp_client.connect((tcp_addr, 7788))
#发送数据
send_data = input("发送数据:")
tcp_client.send(send_data.encode())
#接收数据
recv_data = tcp_client.recv(1024)
print(recv_data.decode('gbk'))
#关闭套接字
tcp_client.close()
if __name__ == '__main__':
main()
3.4 TCP服务端
1 socket创建套接字
2 bind绑定IP和port
3 listen使套接字变为可以被动链接
4 accept等待客户端的链接
5 recv/send接收发送数据
import socket
def main():
# 创建 TCP 套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#绑定服务器ip 和 端口号
tcp_server.bind(("192.168.2.119", 7890))
#使套接字变为可以被动链接
tcp_server.listen(128)
#等待客户端链接
new_client_socket, client_addr = tcp_server.accept()
#等待接收客户端数据
recv_data = new_client_socket.recv(1024)
print(client_addr, recv_data.decode('gbk'))
#给客户端发送数据
new_client_socket.send('haha'.encode('gbk'))
#关闭客户端连接和套接字
new_client_socket.close()
tcp_server.close()
if __name__ == '__main__':
main()
上面代码配合网络调试助手测试
3.5 TCP服务端为多个客户端服务
'''
为多个客户端服务
1 socket创建套接字
2 bind绑定IP和port
3 listen使套接字变为可以被动链接
4 accept等待客户端的链接
5 recv/send接收发送数据
6 关闭连接,关闭套接字
'''
import socket
def main():
# 创建TCP套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#绑定连接ip 和 端口号
tcp_server.bind(('', 7788))
#使套接字变为可以被动链接
tcp_server.listen(128)
while True:
# print('-----1-----')
#等待客户端连接
new_client_socket, client_addr = tcp_server.accept()
# print('-----2-----')
while True:
#等待接收客户端数据
recv_data = new_client_socket.recv(1024)
print(recv_data.decode('gbk'))
#1、接收客户端发送的数据;2、接收客户端断开的消息 b''
if recv_data:
new_client_socket.send('哈哈,接收到数据反馈'.encode('gbk'))
else:
break
new_client_socket.close()
tcp_server.close()
if __name__ == '__main__':
main()
3.6 TCP文件下载器
TCP客户端
1.创建套接字
2.目的信息 服务器的ip port
3.连接服务器
4.输入要下载的文件名称
5.发送文件下载请求
6.接收对方发送过来的数据
7.接收到数据再创建文件
8.关闭套接字
import socket
def main():
# 创建TCP套接字
tcp_socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
tcp_socket_client.connect(("192.168.2.119", 7890))
#
filename = input('请输入下载文件名:')
#发送文件下载请求
tcp_socket_client.send(filename.encode('gbk'))
#接收文件
recv_data = tcp_socket_client.recv(1024 * 1024)
#写入本地文件
if recv_data:
with open('接收' + filename, 'wb') as f:
f.write(recv_data)
#关闭套接字
tcp_socket_client.close()
if __name__ == '__main__':
main()
TCP服务端
1 socket创建套接字
2 bind绑定IP和port
3 listen使套接字变为可以被动链接
4 accept等待客户端的链接
5 recv/send接收发送数据
import socket
def send_file_client(new_client_socket):
# 接收客户端发送过来的数据
file_name = new_client_socket.recv(1024).decode()
print('文件名:', file_name)
content = b""
try:
with open(file_name, 'rb') as f:
content = f.read()
except:
print('no download file:%s' % file_name)
new_client_socket.send(content)
new_client_socket.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#绑定ip 和 端口
tcp_socket_server.bind(("192.168.2.119", 7890))
#使套接字可以变为被动链接
tcp_socket_server.listen(128)
#接收客户端连接
new_client_socket, client_addr = tcp_socket_server.accept()
#调用客户端函数,返回文件内容
send_file_client(new_client_socket)
tcp_socket_server.close()
if __name__ == '__main__':
main()