专业理解: socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口,Socket其实就是使用一个门面模式(门面模式要求一个子系统的外部与其内部的通讯必须经过一个统一的门面(Facade)对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用), 它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来讲,一组简单的接口就是所有.让socket去组织数据.python
简易理解:socket就是一个模块,封装了网络通讯所须要的全部东西.经过调用socket模块实现两个进程之间的链接和通信.(也可称为:IP+Port , IP用于表示互联网中的一台主机的位置,而port则是定位到这个机器上的某个程序.)shell
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 所以,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通信。这也被称进程间通信,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。编程
两个种族:缓存
1.基于网络类型的套接字:AF_INET服务器
(还有AF_INET6被用于ipv6,还有一些其余的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是不多被使用,或者是根本没有实现,全部地址家族中,AF_INET是使用最普遍的一个,python支持不少种地址家族,可是因为咱们只关心网络编程,因此大部分时候我么只使用AF_INET)网络
2.基于文件类型的套接字:AF_UNIXsocket
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,能够经过访问同一个文件系统间接完成通讯tcp
import socket socket.socket(socket_family,socket_type,protocal=0) #socket_family 地址簇 : 能够是 AF_UNIX 或 AF_INET。 #socket_type : 能够是 SOCK_STREAM 或 SOCK_DGRAM。 # protocol : 通常不填,默认值为 0。 ### 获取tcp/ip套接字 # socket.AF_INET: IPV4 IP协议 # socket.SOCK_STREAM : 提供面向链接的稳定数据传输 TCP是流传输 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ### 获取udp/ip套接字 # socket.AF_INET: IPV4 IP协议 # socket.SOCK_DGRAM 使用不连续不可靠的数据包链接 , 数据包 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的链接,(阻塞式)等待链接的到来函数
s.connect() 主动初始化TCP服务器链接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常设计
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 链接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操做的超时时间
s.gettimeout() 获得阻塞套接字操做的超时时间
s.fileno() 套接字的文件描述符
s.makefile() 建立一个与该套接字相关的文件
tcp是基于连接的,必须先启动服务端,而后再启动客户端去连接服务端
### Client 客户端 import socket client=socket.socket() # 建立 socket对象 client.connect(('127.0.0.1',8848)) # 链接服务端地址,端口号8848 # 发送数据 client.send('abcd'.encode('utf-8')) # 客户端 发送字节类型数据 from_server_data=client.recv(1024) # 客户端接收服务端响应的数据 print(from_server_data) client.close() # 关闭客户端链接
### server服务端 import socket server=socket.socket() # 1 . 建立 socket的server对象 server.bind(('127.0.0.1',8848)) # 2 . 绑定IP 和端口 # 3. 监听 server.listen(5) # 4. 接受链接 conn,addr=server.accept() # 程序等待 print(conn,addr) # 打印 conn 链接信息 ,和addr地址信息 data=conn.recv(1024) # 接收客户端发送的数据 最多接收1024字节 conn.send(data.upper()) # 发送给客户端数据 conn.close() # 关闭链接 server.close() #关闭服务
### client import socket client=socket.socket() client.connect(('127.0.0.1',8848))# 链接 # 发送数据 while 1: user_input=input('>>').strip().encode('utf-8') # 用户输入的字符串数据,转换成字节格式 client.send(user_input) # 客户端 发送字节数据 from_server_data=client.recv(1024) # 接收服务端 返回的数据 ,每次接收1024字节 print(f'来自服务端的信息:{from_server_data.decode("utf8")}') client.close()
### server服务端 import socket server=socket.socket() # 1 . 建立 server对象 server.bind(('127.0.0.1',8848)) # 2 . 绑定IP 和端口 # 3. 监听 server.listen(5) # 4. 接受链接 conn,addr=server.accept() # 程序等待 print(conn,addr) while 1 : # 循环去 data=conn.recv(1024) # 接收数据 最多接收1024字节 print(f'来自客户端{addr}的信息{data.decode("utf-8")}') to_client=input('>>>').strip().encode('utf-8') conn.send(to_client) # 发送数据 conn.close() # 关闭链接 server.close() #关闭服务
### 客户端 client , # 启动多个客户端, 依次排队, 当第一个链接断开时,第二个链接就会链接服务端 import socket client =socket.socket() client.connect(('127.0.0.1',9999)) while 1: try: user_input=input('请输入信息:>>>').strip().encode('utf-8') if user_input.upper()==b'Q': client.send(user_input) break client.send(user_input) ser_data=client.recv(1024) print(f'来自服务端的信息:{ser_data.decode("utf-8")}') except ConnectionResetError: break client.close()
### server 服务端 import socket server=socket.socket() server.bind(('127.0.0.1',9999)) server.listen(2) while 1: conn,addr=server.accept() print(conn,addr) while 1: try: cli_data=conn.recv(1024) print(f'来自客户端:{addr}消息: {cli_data.decode("utf-8")}') if cli_data.upper()==b'Q': break response=input('回复消息:>>').strip().encode('utf-8') conn.send(response) except ConnectionResetError: break conn.close() # 当上一个conn 链接已经关闭或断开时,进入下一次循环,等待新的链接 server.close()
# -*-coding:utf-8-*- import subprocess while 1: user_input=input('请输入指令:').strip() obj=subprocess.Popen(user_input, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) if obj.stdout: print(f'正确信息: {obj.stdout.read().decode("gbk")}') else: print(f'错误信息: {obj.stderr.read().decode("gbk")}')
什么是粘包:
客户端不能一次性接收完服务器返回的信息.这些没有接收完的信息会保存在一个缓冲区内. 等下次链接再来时,先把上一次没有收完的数据给接收了.
### server import socket import subprocess server =socket.socket() server.bind(('127.0.0.1',8877)) server.listen(5) while 1: conn , addr=server.accept() print(conn,addr) while 1: try: cmd=conn.recv(1024) # 接收客户端发来的cmd 字节指令 print(cmd) # 执行本机cmd命令 obj=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 拼接返回信息 msg_right=obj.stdout.read() msg_err=obj.stderr.read() result=(msg_right+msg_err).decode('gbk').encode('utf-8') print(result.decode('utf-8')) # 向客户端发送结果 conn.send(result) except ConnectionResetError: break conn.close() server.close()
### client import socket client=socket.socket() #链接服务器 client.connect(('127.0.0.1',8877)) while 1: user_input=input('请输入指令:>>>').strip() # 发送指令 以字节形式 client.send(user_input.encode('utf-8')) # 接收返回结果 try: ser_data=client.recv(1024) print(ser_data.decode('utf-8')) except UnicodeDecodeError as e: print(e) client.close()