Python-socket网络编程
socket的基本认识:
socket(套接字):是一个通信端点,一种底层的网络接口。包含了很多套接字协议,可以参考文档:socket文档
socket 地址:进行网络通信的网络地址,主机-端口对,通过这个可以知道,要和谁进行通信
socket 类型:两类,面向连接的套接字和面向无连接的套接字
面向连接的套接字:
- 通信前必须先建立一个连接
- 提供序列化的、可靠的、不重复的数据交付,而且没有记录边界
- 实现面向连接的套接字的基本协议是:传输控制协议(TCP)
无连接的套接字
- 不用建立连接
- 无法保证顺序性、可靠性或重复性,但是确实保存边界,消息是以整体进行发送的
- 实现面向无连接套接字的基本协议是:用户数据报协议(UDP)
客户端/服务器架构
服务器:
就是一系列的硬件或软件,为一个或多个客户端(服务的用户)提供所需的服务。他存在唯一的目的就是等待客户端的请求,并响应他们。
客户端:
用户访问的界面或者说使用的软件,访问服务器,获取自己需要的信息
客户端对服务器的请求是一次性请求,服务器是需要一直运行下去的。客户端的每一次请求,都可以看做是一个事务。
socket模块提供的一些方法
名称 | 描述 |
---|---|
服务器套接字方法 | |
s.bind() | 将地址(ip,port)绑定到套接字上 |
s.listen() | 设置并启动TCP监听器 |
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.detach() | 在未关闭文件描述符的情况下关闭套接字,返回文件描述符 |
面向阻塞的套接字方法 | |
s.setblocking() | 设置套接字的阻塞或非阻塞模式 |
s.settimeout() | 设置阻塞套接字操作的超时时间 |
s.gettimeout() | 获取阻塞套接字操作的超时时间 |
面向文件的套接字方法 | |
s.fileno() | 套接字的文件描述符 |
s.makefile() | 创建与套接字关联的文件对象 |
socket模块使用
要创建套接字,必须使用socket.socket()函数,一般语法如下:
socket(socket_family, socket_type, protocol=0)
# 参数解释:
socket_family: 是AF_UNIX 或 AF_INET
socket_type: 是SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP)
protocol 通常省略,默认是0
创建TCP/IP套接字或UDP/IP套接字如下所示:
# 创建TCP/IP套接字
tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建UDP/IP套接字
udpSocket = socket.socket(socket.AF_INET, socket.SOCK.DGRAM)
使用套接字创建TCP服务器和客户端
"""
TCP服务器:
1. 创建服务器套接字
2. 套接字与地址绑定
3. 监听连接
4. 服务器无线循环等待连接
5. 接受客户端连接
6. 通信循环
7. 对话(接受/发送)
8. 关闭客户端套接字
9. 关闭服务器套接字(可选)
"""
from socket import *
from time import ctime
# 地址和端口
HOST = ''
PORT = 21567
BUFFER_SIZE = 1024
ADDR = (HOST, PORT)
tcp_socket_server = socket(AF_INET, SOCK_STREAM) # 创建服务器套接字
tcp_socket_server.bind(ADDR) # 套接字与地址绑定
tcp_socket_server.listen(5) # 监听连接
# 服务器无限循环等待连接
while True:
print('waiting for connection....')
tcp_client_server, addr = tcp_socket_server.accept() # 接受客户端连接
print('... connect from: ', addr)
# 通信循环
while True:
data = tcp_client_server.recv(BUFFER_SIZE) # 接受客户端发送的消息
if not data:
break
tcp_client_server.send('[%s] %s'.encode('utf-8') % (bytes(ctime(), 'utf-8'), data)) # 向客户端发送信息
tcp_client_server.close() # 关闭客户端套接字
tcp_socket_server.close() # 关闭服务器套接字(可选)
TCP客户端
"""
TCP 客户端:
1. 创建客户端套接字
2. 尝试连接服务器
3. 通信循环
4. 对话
5. 关闭客户端套接字
"""
from socket import *
HOST = '127.0.0.1'
PORT = 21567
BUFFER_SIZE = 1024
ADDR = (HOST, PORT)
tcp_client_server = socket(AF_INET, SOCK_STREAM) # 创建客户端套接字
tcp_client_server.connect(ADDR) # 尝试连接服务器
# 通信循环
while True:
data = input("> ")
if not data:
break
tcp_client_server.send(data.encode('utf-8')) # 客户端发送消息
data = tcp_client_server.recv(BUFFER_SIZE) # 客户端接受消息
if not data:
break
print(data.decode('utf-8'))
tcp_client_server.close() # 关闭客户端连接
使用套接字创建UDP服务器
from socket import *
HOST = '127.0.0.1'
PORT = 21567
Buffer_SIZE = 1024
ADDR = (HOST, PORT)
TARGET_PORT = 7777
def send_message(udp_server):
"""发送消息"""
send_data = input('> ')
udp_server.sendto(send_data.encode('utf-8'), (HOST, TARGET_PORT))
def receive_message(udp_server):
"""接收消息"""
recv_data = udp_server.recvfrom(Buffer_SIZE)
print("%s: %s" % (str(recv_data[1]), recv_data[0].decode('utf-8')))
def main():
"""主流程"""
# 创建套接字
udp_server = socket(AF_INET, SOCK_DGRAM)
# 绑定端口
udp_server.bind(ADDR)
# 循环来处理事件
while True:
# 发送
send_message(udp_server)
# 接受并显示
receive_message(udp_server)
if __name__ == '__main__':
main()
使用套接字创建UDP客户端
from socket import *
HOST = '127.0.0.1'
PORT = 7777
BUFFER_SIZE = 1024
ADDR = (HOST, PORT)
def main():
"""主流程"""
udp_client = socket(AF_INET, SOCK_DGRAM)
udp_client.bind(ADDR)
while True:
msg, add = udp_client.recvfrom(BUFFER_SIZE)
print("%s: %s" % (str(add), msg.decode('utf-8')))
send_data = input('> ')
udp_client.sendto(send_data.encode('utf-8'), add)
if __name__ == '__main__':
main()