Socker介绍
Python 提供了两个基本的 socket 模块:
- Socket 它提供了标准的BSD Socket API
- SocketServer 它提供了服务器重心,可以简化网络服务器的开发
Socket类型
套接字格式:socket(family, type[,protocal])
使用给定的套接族,套接字类型,协议编号(默认为0)来创建套接字。
socket类型 | 描述 |
---|---|
socket.AF_UNIX | 用于同一台机器上的进程通信(既本机通信) |
socket.AF_INET | 用于服务器与服务器之间的网络通信 |
socket.AF_INET6 | 基于IPV6方式的服务器与服务器之间的网络通信 |
socket.SOCK_STREAM | 基于TCP的流式socket通信 |
socket.SOCK_DGRAM | 基于UDP的数据报式socket通信 |
socket.SOCK_RAW | 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次SOCK_RAW也可以处理特殊的IPV4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头 |
socket.SOCK_SEQPACKET | 可靠的连续数据包服务 |
常见的套接字对象方法和属性
名称 | 描述 |
---|---|
服务端 | 服务器套接字方法 |
s.bind(ADDR) | 将地址(主机名、端口号对)绑定到套接字上 |
s.listen([backlog]) | 设置并启动 TCP 监听器,如果指定backlog,则必须至少为0(如果低于0,则设置为0); |
s.accept() | 被动接受 TCP 客户端连接,一直等待直到连接到达(阻塞) |
客户端 | 客户端套接字方法 |
s.connect() | 主动发起 TCP 服务器连接 |
s.connect_ex() | connect()的扩展版本,此时会以错误码的形式返回问题,而不是抛出一个异常 |
普通通用 | 普通的套接字方法 |
s.recv() | 接收 TCP 消息 |
s.recv_into() | 接收 TCP 消息到指定的缓冲区 |
s.send() | 发送 TCP 消息 |
s.sendall() | 完整地发送 TCP 消息 |
s.recvfrom() | 接收 UDP 消息 |
s.recvfrom_into() | 接收 UDP 消息到指定的缓冲区 |
s.sendto() | 发送 UDP 消息 |
s.getpeername() | 连接到套接字(TCP)的远程地址 |
s.getsockname() | 当前套接字的地址 |
s.getsockopt() | 返回给定套接字选项的值 |
s.setsockopt() | 设置给定套接字选项的值 |
s.shutdown() | 关闭连接 |
s.close() | 关闭套接字 |
阻塞 | 面向阻塞的套接字方法 |
s.setblocking() | 设置套接字的阻塞或非阻塞模式 |
s.settimeout() | 设置阻塞套接字操作的超时时间 |
s.gettimeout() | 获取阻塞套接字操作的超时时间 |
文件方法 | 面向文件的套接字方法 |
s.fileno() | 套接字的文件描述符 |
s.makefile() | 创建与套接字关联的文件对象 |
属性 | 数据属性 |
s.family | 套接字家族 |
s.type | 套接字类型 |
s.proto | 套接字协议 |
通信模型
编程思想
1.操作IP
# 127.0.01 本地测试ip
# 0.0.0.0 局域网可用ip
# 192.168.1.0 网段
# 192.168.1.1 网关
# 192.168.1.255 广播地址
import socket
# 获取主机名
hostname = socket.gethostname()
# 通过主机名解析IP
IP = socket.gethostbyname(hostname)
# 十进制转二进制
print(socket.inet_aton('192.168.1.190'))
# 结果为\xc0\xa8\x01\xbe
# 二进制转十进制
print(socket.inet_ntoa('\xc0\xa8\x01\xbe'))
# 结果为:192.168.1.190
2.操作端口
# 应用层端口:1–65535
# 众所周知的服务端口:1–255
# 系统端口:256–1023
socket.getservbyname('http') # 结果为80
网络编程
服务端实现
import socket
# 创建TCP套接字
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 绑定IP地址和端口 其中127.0.0.1代表回环地址,只能用于当前计算机
server.bind(('127.0.0.1', 8080))
# 建立半链接池,允许存放5个请求
server.listen(5)
# 等待建立连接请求,会返回两个值,一个是连接状态,一个是连接的客户端IP与端口
conn,ip_addr = server.accept()
# 接收客户端传递的数据,只接收1024个字节数据
res = conn.recv(1024)
# 查看一下连接客户端的IP与端口
print(ip_addr)
# 接收到的是Bytes类型,需要解码
print(res.decode('utf-8'))
# 关闭与客户端的连接
conn.close()
# 关闭套接字
server.close()
客户端实现
import socket
# 创建套接字对象,AF_INET基于TCP/UDP通信,SOCK_STREAM以数据流的形式传输数据,这里就可以确定是TCP了
client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 连接服务端
client.connect(('127.0.0.1',8080))
# 向服务端发送数据,需要转换成Bytes类型发送
client.send('Hello'.encode('utf-8'))
# 套接字关闭
client.close()
练习
**功能:**客户端获取键盘输入,服务端打印
**注意:**服务端应先启动
1.服务端
# coding:utf-8
# 功能:服务端实现
# 时间:2023-03-07
import socket
# 设置IP和端口
HOST = '127.0.0.1'
PORT = 8001
# 创建TCP套接字,绑定IP,建立连接池
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(5)
# 打印IP
print('Server start at: %s:%s' %(HOST, PORT))
print('wait for connection...')
# 接收客户端请求
while True:
conn, addr = s.accept()
# 客户端IP
print('Connected by ', addr)
while True:
data = conn.recv(1024)
print(data.decode('utf-8'))
conn.send("server received you message.".encode('utf-8'))
# conn.close()
2.客户端
# coding:utf-8
# 功能:客户端实现
# 时间:2023-03-07
import socket
HOST = '127.0.0.1'
PORT = 8001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 请求连接
s.connect((HOST, PORT))
while True:
cmd = input("Please input msg:")
# 编码
s.send(cmd.encode('utf-8'))
data = s.recv(1024)
# 解码
print(data.decode('utf-8'))
#s.close()
# 客户端
dataSocket, addr = listenSokcet.accept()
while True:
data = dataSocket.recv(1024)
if not data: # 若对方调用close(),则返回空字节
break
# 读取的字节为bytes类型,需解码为字符串
info = data.decode()
print(f"收到的消息为:{info}")
# 发送的数据为bytes类型,需进行编码
dataSocket.send(f'收到的信息为:{info}'.encode())
# 服务端调用close()关闭socket
dataSocket.close()
listenSocket.close()
Windows查看端口是否被占用
cmd输入
netstat -an | find /i "xxxx"