socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
- file模块是针对某个指定文件进行【打开】【读写】【关闭】
- socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】
socket服务端与客户端交流示意图:
socket()模块函数
使用socket.socket()函数来创建套接字,语法如下:
socket(socket_family,socket_type,protocol=0)
如前所述,参数一:socket_family(地址簇)
socket.AF_UNIX 只能用于单一的UNIX系统进程间通信
socket.AF_INET IPV4(默认)
socket.AF_INET6 IPV6
参数二:socket_type(类型)
socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDPsocket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务
参数三:protocol(协议)
0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
创建一个TCP/IP的套接字,你要这样调用socket.socket():
tcpsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
同样的,创建一个UDP/IP的套接字,你要这样:
udpsocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
套接字对象(内建)方法:
函数 | 描述 |
服务器套接字函数 | |
s.bind(address) | 绑定地址(主机名,端口号对)到套接字 |
s.listen(backlog) | 开始TCP监听 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待链接的到来 |
客户端套接字函数 | |
s.connect() | 主动初始化TCP服务器连接 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数 | |
s.recv() | 接收TCP数据 |
s.send() | 发送TCP数据 |
s.sendall() | 完整发送TCP数据(不停调用s.send()) |
s.recvfrom() | 接收UDP数据 |
s.sendto() | 发送UDP数据 |
s.getpeername() | 链接到当前套接字的远端的地址(TCP连接) |
s.getsockname() | 当前套接字的地址 |
s.getsockopt() | 返回指定套接字的参数 |
s.setsockopt() | 设置指定套接字的参数 |
s.close() | 关闭套接字 |
面向模块的套接字函数 | |
s.setblocking() | 设置套接字的阻塞与非阻塞模式 |
s.settimeout() | 设置阻塞套接字操作的超时时间 |
s.gettimeout() | 得到阻塞套接字操作的超时时间 |
面向文件的套接字函数 | |
s.fileno() | 套接字的文件描述 |
s.makefile() | 创建一个与该套接字相关联的文件对象 |
例:(win环境)
server端
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print(‘server waiting...‘) conn,addr = sk.accept() client_data = conn.recv(1024) print(str(client_data,‘utf8‘)) conn.sendall(bytes(‘不要回答,不要回答,不要回答‘,‘utf8‘)) conn.close()
client端
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.connect(ip_port) sk.sendall(bytes(‘请求占领地球‘,‘utf8‘)) server_reply = sk.recv(1024) print(str(server_reply,‘utf8‘)) sk.close()
连续交互通信实例:
server端:(win环境)
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print(‘server waiting...‘) conn,addr = sk.accept() client_data = conn.recv(1024) print(str(client_data,‘utf8‘)) conn.sendall(bytes(‘不要回答,不要回答,不要回答‘,‘utf8‘)) while True: try:
client_data = conn.recv(1024) print(str(client_data,‘utf8‘)) server_response = input(‘>>>:‘).strip() except Exception:
print("client closed,break")
break
conn.send(bytes(server_response,‘utf8‘)) conn.close()
server端:(Linux环境)
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print(‘server waiting...‘) conn,addr = sk.accept() client_data = conn.recv(1024) print(str(client_data,‘utf8‘)) conn.sendall(bytes(‘不要回答,不要回答,不要回答‘,‘utf8‘)) while True: client_data = conn.recv(1024) print(str(client_data,‘utf8‘))
server_response = input(‘>>>:‘).strip()
if not client_data:break conn.send(server_response) conn.close()
client端:
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.connect(ip_port) sk.sendall(bytes(‘请求占领地球‘,‘utf8‘)) server_reply = sk.recv(1024) print(str(server_reply,‘utf8‘)) while True: user_input = input(">>>").strip() sk.send(bytes(user_input,‘utf8‘)) server_reply = sk.recv(1024) print(str(server_reply,‘utf8‘)) sk.close()
模拟实现简单ssh功能:
server端:
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket import subprocess ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print(‘server waiting...‘) conn,addr = sk.accept() while True: client_data = conn.recv(1024) if not client_data:break print("recv cmd:",str(client_data,‘utf8‘)) cmd = str(client_data,‘utf8‘).strip() cmd_call = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) cmd_result = cmd_call.stdout.read() if len(cmd_result) == 0: cmd_result = b"cmd execution has no output..." ack_msg = bytes("CMD_RESULT_SIZE|%s"%len(cmd_result),"utf8") conn.send(ack_msg) client_ack = conn.recv(50) if client_ack.decode() == "CLIENT_READY_TO_RECV": conn.send(cmd_result) conn.close()
client端:
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = (‘127.0.0.1‘,9999) sk = socket.socket() sk.connect(ip_port) while True: user_input = input("cmd:").strip() if len(user_input) == 0:continue if user_input == "q":break sk.send(bytes(user_input,‘utf8‘)) #ack_msg = b"CMD_RESULT_SIZE|%s",len(cmd_result) server_ack_msg = sk.recv(100) cmd_res_msg = str(server_ack_msg.decode()).split("|") print("server response:",cmd_res_msg) if cmd_res_msg[0] == "CMD_RESULT_SIZE": cmd_res_size = int(cmd_res_msg[1]) sk.send(b"CLIENT_READY_TO_RECV") res = ‘‘ received_size = 0 while received_size < cmd_res_size: data = sk.recv(500) received_size += len(data) res += str(data.decode()) else: print(str(res)) print("----------recv doen----------") sk.close()