首页 技术 正文
技术 2022年11月12日
0 收藏 556 点赞 2,404 浏览 6052 个字

Socket接口

Socket: Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。

1.简单的套接字通信

服务端

import socket#1.买手机 创建一个套接字对象
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #基于网络通信的套接字 (TCP)
# print(phone)#2.绑定手机卡(ip地址)
phone.bind(('127.0.0.1',8080)) # 端口0-65535: 0-1024是给操作系统使用的#3.开机
phone.listen(5) #最大挂起的链接数#4.等电话链接
print('starting...')
conn,client_addr=phone.accept() #conn 电话线 拿到可以收发信息的管道
#accept 对应客户端的connect 三次握手#5.收,发消息
data = conn.recv(1024) #1.单位:bytes 2. 1024代表接受1024个bytes
print('客户端的数据',data)conn.send(data.upper())#6.挂电话
conn.close()#7.关机
phone.close()

客户端

import socket#1.买手机 客户端的phone 相当于服务端的conn
phone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# print(phone)#2.拨号 (服务端的ip 和服务端的 端口)
phone.connect(('127.0.0.1',8080)) #0-65535: 0-1024是给操作系统使用的#3.发收消息 bytes型
phone.send('hello'.encode('utf-8'))
data = phone.recv(1024)
print(data)#4.关闭
phone.close()

2.加上通信循环

服务端

import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)print('starting...')
conn,client_addr=phone.accept()
print(client_addr)while True: #通信循环
data = conn.recv(1024)
print('客户端的数据',data)
conn.send(data.upper())conn.close()
phone.close()

客户端

import socketphone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081)) #0-65535: 0-1024是给操作系统使用的while True:
msg = input('>>: ').strip()
phone.send(msg.encode('utf-8'))
data = phone.recv(1024)
print(data)
phone.close()

3.C与S的bug修复

Socket接口

BUG问题:

1.端口的重复使用

问题:重启服务端时可能会遇到

Socket接口

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址

windows解决方法

#服务端代码
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip端口重用
phone.bind(('127.0.0.1',8080))

linux解决方法

发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
vi /etc/sysctl.conf编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30然后执行 /sbin/sysctl -p 让参数生效。net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

2.客户端关闭

服务端

import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip 端口重用
phone.bind(('127.0.0.1',8080))
phone.listen(5)print('starting...')
conn,client_addr=phone.accept()
print(client_addr)while True: #通信循环
try:
data = conn.recv(1024)
# if not data:break #适用于linux操作系统
print('客户端的数据',data)
conn.send(data.upper())
except ConnectionResetError:#使用于windows操作系统
breakconn.close()
phone.close(

客户端

客户端应用程序在发送的时候:send==空–>客户端的操作系统内存 收到为空—> 不会调用任何协议,没有发送数据给,服务端的操作系统内存

服务端应用程序在接受的时候:服务端的操作系统内存由于没有接收到数据,所以一直卡在,应用程序的recv接受过程

import socketphone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) #0-65535: 0-1024是给操作系统使用的while True:
msg = input('>>: ').strip() # msg =''
if not msg:continue
phone.send(msg.encode('utf-8')) #phone.send(b'')
# print('has send') #验证可以发空
# >>: has send
data = phone.recv(1024)
# print('has recv') #验证在发空的情况下 是否可以接受消息
#>>: has send
print(data.decode('utf-8')) phone.close()

4.加上链接通信

服务端一直对外进行服务:可以保证客户端一个一个链接进来

链接新的客户端的条件:停止前一个客户端

服务端

import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip 端口重用
phone.bind(('127.0.0.1',8080))
phone.listen(5)print('starting...')
while True: # 链接循环
conn,client_addr=phone.accept()
print(client_addr) while True: #通信循环
try:
data = conn.recv(1024)
# if not data:break #适用于linux操作系统
print('客户端的数据',data)
conn.send(data.upper())
except ConnectionResetError:#使用于windows操作系统
break
conn.close()phone.close()

客户端

import socketphone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) #0-65535: 0-1024是给操作系统使用的while True:
msg = input('>>: ').strip() # msg =''
if not msg:continue
phone.send(msg.encode('utf-8')) #phone.send(b'')
# print('has send') #验证可以发空
# >>: has send
data = phone.recv(1024)
# print('has recv') #验证在发空的情况下 是否可以接受消息
#>>: has send
print(data.decode('utf-8'))phone.close()

客户端1

import socketphone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) #0-65535: 0-1024是给操作系统使用的while True:
msg = input('>>: ').strip() # msg =''
if not msg:continue
phone.send(msg.encode('utf-8')) #phone.send(b'')
# print('has send') #验证可以发空
# >>: has send
data = phone.recv(1024)
# print('has recv') #验证在发空的情况下 是否可以接受消息
#>>: has send
print(data.decode('utf-8'))phone.close()

5.ssh远程执行命令

windows命令:

  • dir: 查看某一文件夹下的子文件名与子文件夹名
  • ipconfig: 查看本地网卡的ip信息
  • tasklist: 查看运行的进程

linux命令:

  • ls
  • ifconfig
  • pa aux

问题:想要在服务端拿到命令,并且将命令的结果返回给客户端

通过os.system可以执行系统命令,但是只能返回0或者1(命令正确 0 ,命令错误 1),无法返回出系统命令的执行结果

import os
res = os.system('dir E:')
print('命令的结果: ', res)

解决方法:

创建管道:

import subprocess
obj = subprocess.Popen('dirsadas E:',shell=True,
stdout=subprocess.PIPE, #丢到管道里面shell是命令解释器的意思,启动一个程序来解析,前面的字符串,解析成相应的命令
stderr=subprocess.PIPE)
print(obj)
# print('stout 1--->: ',obj.stdout.read().decode('gbk')) #第一次从管道中取走了数据
# print('stout 2--->: ',obj.stdout.read().decode('gbk')) #第二次没有值所以为空print('stderr 1--->: ',obj.stderr.read().decode('gbk')) # 拿到错误管道的数据#在解码的时候,必须考虑到编码的格式,在管道里执行系统命令的是要提交给系统,
# 所以判断出编码的格式是 windows默认的编码gbk

服务端

import socket
import subprocessphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip 端口重用
phone.bind(('127.0.0.1',8080))
phone.listen(5)print('starting...')
while True: # 链接循环
conn,client_addr=phone.accept() #接受客户端链接
print(client_addr) while True: #通信循环
try:
#1.收命令
data = conn.recv(1024)
print('客户端的数据',data) #2.执行命令,拿到结果
obj = subprocess.Popen(data.decode('utf-8'), shell=True,
stdout=subprocess.PIPE, # 丢到管道里面
stderr=subprocess.PIPE) # shell是命令解释器的意思,启动一个程序来解析,前面的字符串,解析成相应的命令 stdout = obj.stdout.read()
stderr = obj.stderr.read() #3.把命令的结果返回给客户端
conn.send(stdout+stderr) # '+'是可以优化的点 except ConnectionResetError:# 使用于windows操作系统
break
conn.close()phone.close()

客户端

import socketphone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)phone.connect(('127.0.0.1',8080))
while True:
#1.发命令
cmd = input('>>: ').strip() #dir C:
if not cmd:continue
phone.send(cmd.encode('utf-8')) #2.拿命令的结果,并打印
data = phone.recv(1024) # 1024是一个坑
print(data.decode('gbk')) #系统默认的编码phone.close()
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,907
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,432
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,247
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,058
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,690
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,728