Python的socket模块与交互式指令

Python的socket模块与交互式指令

socket简介

在编程的过程中,我们需要使用网络编程,这时我们不得不和网络通信的底层基础打交道了.我们必须让自己传输的数据符合网络通信的基本协议,即TCP/IP协议,但是网络通信协议本身很复杂.我们不可能在编程的过程中还自己去对数据进行封包处理,这是便出现了socket帮助我们处理相关的数据传输,在其他语言里也可以使用socket帮我们处理相关问题.

socket本质就是一组接口,是在应用层与TCP/IP协议族通信中间的一个抽象层,庞大复杂的TCP/IP协议族我们便可以不用过多关注,而只需要通过socket提供的接口就可以相互连接.

socke模块中的基本命令
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的服务端和客户端示例
TCP服务端
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
##网络编程需要调用AF_INET,而SOCK_STREAM代表数据流,即TCP方式
phone.bind(('192.168.1.101',9000))
##绑定IP地址和端口,必须是元组
phone.listen(5)
##设置监听数量
while True:
    conn, addr = phone.accept()
    ##得到内容对象和地址
    while True:
        try:  ##异常处理特殊情况
            feedback = conn.recv(1024)
            ##得到内容对象传来的值,里面规定字节数量
            print(feedback.decode("UTF-8"))
            ##编译,因为只有被编译的字符才能被传输
            msg = input(">>:")
            conn.send(msg.encode("UTF-8"))
            ##发送
        except Exception:
            break

conn.close() ##关闭连接了的对象
phone.close() ##关闭服务器
TCP客户端
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect_ex(('192.168.1.101',9000)) ##连接对象
while True:
    msg = input(">>:")
    phone.send(msg.encode("UTF-8")) ##发送消息
    feedback = phone.recv(1024) ##返回消息
    print(feedback.decode("UTF-8"))
phone.close() ##关闭对象
问题

可能在多次开启关闭服务器的时候,会出现IP地址已经被使用了的情况,我们可以用以下方法解决:

phone = socket(AF_INIT, SOCKET_STREAM)
phone.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
phone.bind(('192.168.1.101',9000))

####UDP的服务端和客户端示例

UDP的服务端
from socket import *
ip_addr = ('192.168.1.101',9000)
buff_size = 1024
udp_server = socket(AF_INET, SOCK_DGRAM)
##SOCK_DGRAM表示UDP方式
udp_server.bind(ip_addr)
##绑定IP地址和端口
while True:
    data, addr = udp_server.recvfrom(buff_size)
    ##受信息
    print(data.decode("utf-8"))
    udp_server.sendto(data.upper(), addr)
    ##发信息
UDP的客户端
from socket import *

ip_addr = ('192.168.1.101',9000)
buff_size = 1024
udp_client = socket(AF_INET, SOCK_DGRAM)
while True:
    msg = input(">>:")
    udp_client.sendto(msg.encode("utf-8"), ip_addr)
    ##不需要绑定,只需要传一个地址
    date, addr = udp_client.recvfrom(buff_size)
    print(date.decode("utf-8"))
subprogress模块

TCP和UDP比较
TCPUDP
传输方式数据流(STREAM)数据报(DGRAM)
导致问题粘包丢包
接待对象一个多个
连接需要连接线不需要连接线

TCP是以数据流的方式,在数据很多时,会多次地不分内容关联性地传输给对方内核态缓存,当用户态缓存来取数据时,并不知道数据的开头和结尾,那么就出现了粘包现象.因此粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的,所以通过TCP方式不能发送空.

然而,UDP方式是以信息为单位传输数据,在数据里面包含了开头和结尾的界限,因此不会出现粘包的现象,但是当传输来的数据被储存在内核态缓存里面时,如果应用态缓存没有一次性的取完数据,那么数据就会被丢弃

解决了粘包现象的远程指令程序
客户端
from socket import *

ip_port = ('127.0.0.1', 9000)

client = socket(AF_INET, SOCK_STREAM)
client.connect_ex(ip_port)
while True:
    command = input(">>:")
    if not command: continue
    client.send(command.encode("utf-8"))
    feedback_of_length = int(client.recv(1024).decode("gbk"))  #先得到数据的长度
    client.send("OK".encode("gbk"))   #并且发送可以传输了的命令
    all_data = b""  
    data_length = 0
    while data_length < feedback_of_length:
        all_data += client.recv(1024)  #循环地把数据联结在一起
        data_length = len(all_data)   
    last_date = all_data.decode("gbk")  ##最后解码
    print(last_date)
    
client.close()
服务端
from socket import *
import subprocess

ip_port = ('127.0.0.1', 9000)
buff_size = 5

server = socket(AF_INET, SOCK_STREAM)
server.bind(ip_port)
server.listen(buff_size)
while True:
    conn, addr = server.accept()
    while True:
        try:
            cmd = conn.recv(1024)
            if not cmd: continue
            res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                   stderr = subprocess.PIPE,
                                   stdin = subprocess.PIPE,
                                   stdout = subprocess.PIPE
            )
            err = res.stderr.read()
            if not res:
                get_res = "Run Perfectly"
            elif err:
                get_res = err
            else:
                get_res = res.stdout.read()
            length_of_res = len(get_res)  #发送数据长度
            conn.send(str(length_of_res).encode("gbk")) 
            last_info = conn.recv(1024)   #得到是否传输的指令
            if last_info.decode("utf-8") == "OK":
                 conn.send(get_res)
        except Exception:
            break
socketserver实现并发
TCP版服务端
import socketserver

class MyServer(socketserver.BaseRequestHandler):  ##必须要继承这个父类
	def handle(self):  ##必须要重新定义这个方法
		while True:
			try:
				data = self.request.recv(1024)  ##recv就相当于conn了
				if not data: break
				print(data.decode("utf-8"), self.client_address) ##只有data和client_address这两个量 
				self.request.sendall(data)  
			except Exception:
				break


if __name__ == "__main__":
	s = socketserver.ThreadingTCPServer(('192.168.1.101',9001), MyServer)  ##实例化一个对象
	s.serve_forever()  ##永远运行

UDP版服务端
import socketserver

class MyServer(socketserver.BaseRequestHandle):
	def handle(self):
        ##(b'ad', <socket.socket fd=444, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0,
        ##   laddr=('192.168.1.101', 8081)>)  request是一个元组
		print(self.request[0].decode("utf-8"))
		self.request[1].sendto(self.request[0], self.client_address)

if __name__ == "__main__":
	s = socketserver.ThreadingUDPServer(('192.168.1.101',8080), MyServer)
	s.server_forever()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值