链条传动

砥砺前行,不忘初心!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

socket基本语法

#!/usr/bin/env python
# -*- coding: utf-8 -*-


'''
python3 socket收发消息都是只能使用bytes类型,而python2.7则可以使用str类型
'''

import socket

#创建socket对象
s = socket.socket()  #创建socket对象

s.settimeout(5)   #设置超时时间
s.getpeername()  #客户端使用,返回服务端的套接字地址(ip、端口号)

#连接服务端
ip_port = ('127.0.0.1',9999)  #定义ip、端口号
s.connect(ip_port)  #socket对象连接服务端。(ip、端口号一定是元组形式) ----连接失败会报错
#s.connect_ex(ip_port)   #功能同上,不过如果连接失败会返回一个错误编码(不报错)


#发消息
send_data = '你好'
s.send(bytes(send_data,encoding='utf-8'))    #发送消息,成功返回发送的字节数-----python3只能发送字节类型(bytes),python2.7可以直接发送字符串
#s.sendall(bytes(send_data,encoding='utf-8'))   #发送所有数据,成功返回None,失败报错

#收消息
recv_data = s.recv(1024)


#关闭
s.close()
Client
#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
python3 socket收发消息都是只能使用bytes类型,而python2.7则可以使用str类型
'''

'''
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
参数一:地址簇
  socket.AF_INET IPv4(默认)
  socket.AF_INET6 IPv6
  socket.AF_UNIX 只能够用于单一的Unix系统进程间通信
参数二:类型
  socket.SOCK_STREAM  流式socket , for TCP (默认)
  socket.SOCK_DGRAM   数据报式socket , for UDP
    socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理
                    特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要
                    执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  socket.SOCK_SEQPACKET 可靠的连续数据包服务
参数三:协议
  0  (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
'''

import socket

#创建socket对象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)  #创建socket对象


#绑定
ip_port = ('127.0.0.1',9999)  #定义ip、端口号
s.bind(ip_port)  #socket对象绑定ip、端口号(ip、端口号一定是元组形式)

s.getsockname()  #服务端使用,返回服务端自身的套接字地址(ip、端口号)

#监听,并设置最大挂起连接数
s.listen(5)  #监听,除了正在连接的客户端,最多还能能挂起5个连接,超过之后就拒绝连接


#获取客户端连接
conn, addr = s.accept()   #获取客户端的scoket对象conn和客户端的地址address(ip、端口号)


#收发消息
recv_data = conn.recv(1024)   #socket获取的客户端对象(conn)用来接收消息
print(str(recv_data,encoding='utf-8'))
send_data = '你好'
conn.send(bytes(send_data,encoding='utf-8'))   #socket获取的客户端对象(conn)用来发送消息-----python3只能发送字节类型(bytes),python2.7可以直接发送字符串

#关闭客户端对象
conn.close()
Server

 

socket交互

简单交互

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import socket

#客户端创建socket对象
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#使用connect方法连接服务端,连接失败会报错
#也可以使用connect_ex方法,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回失败编码,例如:10061
client.connect(ip_port)

while True:
    # 从服务端获取数据
    recv_data = client.recv(1024)
    print('Server:',str(recv_data,encoding='utf-8'))
    # 客户端发送数据
    s = input('Client:').strip()
    if len(s) == 0:
        break
    client.send(bytes(s,encoding='utf-8'))
    if s == 'exit':
        break
Client
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket

#创建一个socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#绑定ip和端口号
sock.bind(ip_port)
#设置最大连接数
sock.listen(5)


while True:
    #使用accept方法获取一个客户端连接
    #获取客户端的scoket对象conn和客户端的地址(ip、端口号)address
    conn,address = sock.accept()
    # 给客户端发信息
    send_data = 'Hello.'
    conn.send(bytes(send_data,encoding='utf-8'))
    while True:
        try:
            # 接收客户端消息
            recv_data = conn.recv(1024)
            print('Client:',str(recv_data,encoding='utf-8'))
            #检测客户端发出退出指令,关闭连接
            if str(recv_data,encoding='utf-8') == 'exit':
                break
            s = input('Server:').strip()
            if len(s) == 0:
                break
            conn.send(bytes(s,encoding='utf-8'))
        except Exception as e:
            break

    # 关闭客户端的socket连接
    conn.close()
Server

 

简单ssh交互

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import socket

#客户端创建socket对象
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#使用connect方法连接服务端,连接失败会报错
#也可以使用connect_ex方法,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回失败编码,例如:10061
client.connect(ip_port)

while True:
    # 客户端发送数据
    s = input('Client:').strip()
    if len(s) == 0:
        break
    client.send(bytes(s,encoding='utf-8'))
    if s == 'exit':
        break

    # 从服务端获取数据
    recv_data = client.recv(4096)
    print('Server:',str(recv_data,encoding='utf-8'))
    # print(str(recv_data))
Client
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import subprocess

#创建一个socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#绑定ip和端口号
sock.bind(ip_port)
#设置最大连接数
sock.listen(5)


while True:
    #使用accept方法获取一个客户端连接
    #获取客户端的scoket对象conn和客户端的地址(ip、端口号)address
    conn,address = sock.accept()
    while True:
        try:
            # 接收客户端消息
            recv_data = conn.recv(1024)
            #检测客户端发出退出指令,关闭连接
            if str(recv_data,encoding='utf-8') == 'exit':
                break

            p = subprocess.Popen(str(recv_data,encoding='utf-8'),shell=True,stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,stderr=subprocess.PIPE)  #执行命令
            res = p.stdout.read()   #只能读取一次(读,并取出),第二次读取就为空
            if len(res) == 0:   #判断输出结果的长度,如果为0,表示命令执行错误
                res = p.stderr.read()  #读取错误信息
            send_data = str(res,encoding='gbk')  #将结果解码
            # print(send_data)
            conn.send(bytes(send_data,encoding='utf-8'))   #将结果发送到客户端
        except Exception as e:
            break

    # 关闭客户端的socket连接
    conn.close()
Server

 

粘包问题

#!/usr/bin/env python
# -*- coding: utf-8 -*-


'''
粘包:客户端每次接收数据都有大小限制(如:1024),当接收的数据小于服务端发送的数据时(数据没有接收完),多余的数据就会堆积,
当客户端下次再从服务端获取数据时,先获得的则是上次服务端没有传完的数据。这就是粘包现象

那么怎么才能使每次服务端向客户端发送的数据完全接收呢?
解决:服务端告诉客户端要发送的数据长度,客户端循环来收取服务端发送的数据,直到接收的数据长度等于服务端告诉的长度,就停止接收
'''


import socket

#客户端创建socket对象
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#使用connect方法连接服务端,连接失败会报错
#也可以使用connect_ex方法,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回失败编码,例如:10061
client.connect(ip_port)

while True:
    # 客户端发送数据
    s = input('Client:').strip()
    if len(s) == 0:
        break
    client.send(bytes(s,encoding='utf-8'))
    if s == 'exit':
        break


    ready_data = str(client.recv((1024)),encoding='utf-8')  #获取服务端发送过来的数据长度信息
    if ready_data.startswith('Ready'):
        msg_size = int(ready_data.split('|')[1])  #获取信息长度
        client.send(bytes('Start',encoding='utf-8'))  #告诉服务端可以正式发送数据了

        recv_size = 0  #已经获取的数据长度
        recv_msg = b''   #存放服务端发来的数据(以字节格式进行存放)
        #循环收取服务端发来的数据(每次只接收1024字节)
        while recv_size < msg_size:   #当已经获取的数据长度小于数据总长时,表示数据还没有接收完成,继续接收,直到接收的数据长度大于等于数据总长,就停止接收
            recv_data = client.recv(1024)
            recv_msg += recv_data  #将每次获取的数据拼接到接收的数据字符串上
            recv_size += len(recv_data) #统计已获取数据的长度
            print('数据总长:%s,已接收数据长度:%s'%(msg_size,recv_size))
        print('Server:',str(recv_msg,encoding='utf-8'))
Client
#!/usr/bin/env python
# -*- coding: utf-8 -*-


'''
粘包:客户端每次接收数据都有大小限制(如:1024),当接收的数据小于服务端发送的数据时(数据没有接收完),多余的数据就会堆积,
当客户端下次再从服务端获取数据时,先获得的则是上次服务端没有传完的数据。这就是粘包现象

那么怎么才能使每次服务端向客户端发送的数据完全接收呢?
解决:服务端告诉客户端要发送的数据长度,客户端循环来收取服务端发送的数据,直到接收的数据长度等于服务端告诉的长度,就停止接收
'''

import socket
import subprocess

#创建一个socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
ip_port = ('127.0.0.1',9999)
#绑定ip和端口号
sock.bind(ip_port)
#设置最大连接数
sock.listen(5)


while True:
    #使用accept方法获取一个客户端连接
    #获取客户端的scoket对象conn和客户端的地址(ip、端口号)address
    conn,address = sock.accept()
    while True:
        try:
            # 接收客户端消息
            recv_data = conn.recv(1024)
            #检测客户端发出退出指令,关闭连接
            if str(recv_data,encoding='utf-8') == 'exit':
                break

            p = subprocess.Popen(str(recv_data,encoding='utf-8'),shell=True,stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,stderr=subprocess.PIPE)  #执行命令
            res = p.stdout.read()   #只能读取一次(读,并取出),第二次读取就为空
            if len(res) == 0:   #判断输出结果的长度,如果为0,表示命令执行错误
                res = p.stderr.read()  #读取错误信息

            send_data = bytes(str(res,encoding='gbk'),encoding='utf-8')  #将结果解码,并转换成bytes格式
            #print(str(send_data,encoding='utf-8'))
            conn.send(bytes('Ready|%s'%len(send_data),encoding='utf-8'))   #向客户端发送send_data的长度,为下次正式发送数据做准备
            send_flag = str(conn.recv(1024),encoding='utf-8')  #获取客户端是否发送数据的标志位
            #print(send_flag)
            if send_flag == 'Start':  #标志位为Start,开始发送数据
                conn.send(send_data)   #将结果发送到客户端
        except Exception as e:
            break

    # 关闭客户端的socket连接
    conn.close()
Server

 

posted on 2016-12-02 14:01  链条君  阅读(1472)  评论(0编辑  收藏  举报