网络编程基础之Socket套接字简单应用

一、Socket套接字实现通信循环

  所谓通信循环,简单理解就是客户端可以给服务端循环发送信息并获得反馈的过程。

  1、基础版

    通信循环的程序分为两部分,即两个python模块,分别为客户端.py和服务端.py

    第一部分:服务端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象

phone.bind(('127.0.0.1',3301))  # 绑定指定IP和端口

phone.listen(5) # 开机,监听

conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象

while True:
    data = conn.recv(1024)   # 收讯息
    print('收到来自客户端的讯息:',data)
    conn.send(data.title()) # 发送讯息

conn.close() # 关闭链接

phone.close() # 关机

    第二部分:客户端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
# SOCK_STREAM 指的是TCP协议(或称流式协议)
# SOCK_DGRAM 指的是UDP协议(或称数据报协议)
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
    mes = input('在此输入>>:').strip()
    phone.send(mes.encode('utf-8')) # 发讯息
    data = phone.recv(1024)                 # 收讯息
    print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close()     # 关机

  

  2、改进版

    上面的程序代码其实是存在bug的,比如没有对用户未输入和输入错误等进行异常处理,改进后的程序代码如下:

    第一部分:服务端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用, 解决程序关闭后端口仍然占用的情况

phone.bind(('127.0.0.1',3301))  # 绑定指定IP和端口

phone.listen(5) # 开机,监听

conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象

while True:
    try:
        data = conn.recv(1024)   # 收讯息
        if not data:break  # 仅适用于linux系统
        print('收到来自客户端的讯息:',data)
        conn.send(data.title()) # 发送讯息
    except ConnectionResetError: # 适用于windows系统
        break

conn.close() # 关闭链接

phone.close() # 关机
View Code

    第二部分:客户端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象

phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
    mes = input('在此输入>>:').strip()
    if not mes:continue  # 防止未输入
    phone.send(mes.encode('utf-8')) # 发讯息
    data = phone.recv(1024)                 # 收讯息
    print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close()     # 关机
View Code

    

二、Socket套接字实现链接循环 

  现在我们不满足于简单地通信循环了,我们的需求增加了链接循环,要求程序不光可以进行通信循环,还可以进行链接循环。

  链接循环:我的理解就是服务端一直保持运行,而客户端可以在多个间切换分别与服务端进行连接(简而言之,就是多个客户端与一个服务端间的通信)。

  增加功能后,改变的主要是服务端.py,程序同样是分为两部分。

  第一部分:服务端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用, 解决程序关闭后端口仍然占用的情况

phone.bind(('127.0.0.1',3301))  # 绑定指定IP和端口

phone.listen(5) # 开机,监听
while True:  # 链接循环
    conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象
    while True: # 通信循环
        try:
            data = conn.recv(1024)   # 收讯息
            if not data:break  # 仅适用于linux系统
            print('收到来自客户端的讯息:',data)
            conn.send(data.title()) # 发送讯息
        except ConnectionResetError: # 适用于windows系统
            break

    conn.close() # 关闭链接

phone.close() # 关机

'''
同时有多个客户端发送请求时,链接循环条件下服务端只能一次执行一个,服务端可以一直执行,只有当此客户端结束运行,
才能继续执行另一客户端的请求,以此类推客户端1结束后,客户端2执行,2结束,3才执行
'''

  第二部分:客户端.py

  客户端1.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象

phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
    mes = input('在此输入>>:').strip()
    if not mes:continue  # 防止未输入
    phone.send(mes.encode('utf-8')) # 发讯息
    data = phone.recv(1024)                 # 收讯息
    print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close()     # 关机

  客户端2.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象

phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
    mes = input('在此输入>>:').strip()
    if not mes:continue  # 防止未输入
    phone.send(mes.encode('utf-8')) # 发讯息
    data = phone.recv(1024)                 # 收讯息
    print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close()     # 关机
View Code

  客户端3.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象

phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
    mes = input('在此输入>>:').strip()
    if not mes:continue  # 防止未输入
    phone.send(mes.encode('utf-8')) # 发讯息
    data = phone.recv(1024)                 # 收讯息
    print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close()     # 关机
View Code

三、ssh远程执行命令

  1、几点预备知识

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import os

'''
windows下测试:
    dir:查看某一个文件夹下的子文件名和文件夹名
    ipconfig :查看本地网卡的IP信息
    tasklist:查看运行的进程
'''
# 执行系统命令,并拿到命令的结果

res = os.system('dir')
res = os.system('ipconfig')
print('命令结果:',res) # 命令结果: 0 ,0表示执行成功,非0表示失败

import subprocess

obj = subprocess.Popen('dir',shell=True,
                       stdout=subprocess.PIPE, # 获取'dir'命令执行正确时的返回信息
                       stderr=subprocess.PIPE) # # 获取错误命令执行时的返回信息

print(obj) # <subprocess.Popen object at 0x00000252715E70F0>
print('正确时执行stdout>>:',obj.stdout.read().decode('gbk')) # 因为执行的是windows系统的命令,默认编码是gbk, read()获取的是bytes数据,需要decode解码转为操作系统可读的
print('错误时执行stderr>>:',obj.stderr.read().decode('gbk')) # 如果是linx系统,则默认是utf-8

  2、核心程序仍然分为两部分

    服务端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong

import socket
import subprocess

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用,解决程序结束而端口仍被占用的情况

phone.bind(('127.0.0.1',3301)) # 绑定IP和端口

phone.listen(5) # 监听

while True:
    conn,client = phone.accept() # 获取链接对象和IP、端口

    while True: # 通讯循环
        try:  # 适用于windows系统
            # 1、接受命令
            cmd = conn.recv(1024)
            if not cmd:break # 适用于linux系统
            print('收到来自客户端的命令:',cmd.decode('gbk'))  # 打印接收到的命令
            # 2、执行命令
            obj = subprocess.Popen(cmd.decode('gbk'),shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            print(obj)
            # 3、返回命令执行后的结果
            stdout = obj.stdout.read() # 命令执行正确时结果
            stderr = obj.stderr.read() # 错误命令执行的结果
            conn.send(stdout+stderr)   # 返回执行命令的结果
        except ConnectionResetError:
            break
    conn.close()

phone.close()

    客户端.py

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket

phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 创建套接字对象

phone.connect(('127.0.0.1',3301)) # 建立链接

while True: # 通信循环
    cmd = input('输入命令>>:').strip()
    if not cmd:continue
    phone.send(cmd.encode('gbk')) # 发送命令
    data = phone.recv(1024)  # 接收信息
    print('接收来自服务端的信息:',data.decode('gbk')) # 打印接收的信息

phone.close() # 关机

  

原文地址:https://www.cnblogs.com/schut/p/8671926.html