socket编程

2018-06-17 23:28:54来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

一.socket介绍

1.socket在tcp/ip五层结构中的位置

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

2.类型

  基于文件类型的套接字家族

  套接字家族的名字:AF_UNIX

  unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

  基于网络类型的套接字家族

  套接字家族的名字:AF_INET

  (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

3.套接字工作流程

服务端套接字函数
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的套接字

1.以打电话为例实现套接字通信

 

import socket

#买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
#绑定手机卡
phone.bind(('127.0.0.1',8080))
#开机
phone.listen(5)            #最大挂起的连接数
#等待连接
print('starting...')
conn,client_addr=phone.accept()       #(套接字链接,客户端的ip和port)
print('>>>>>>>')
#收消息
data=conn.recv(1024)            #1024最大的限制
print('客户端消息:',data)
#发消息
conn.send(data.upper())
#挂电话
conn.close()
#关机
phone.close()
服务端
import socket

#买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
#发起连接
phone.connect(('127.0.0.1',8080))
#发消息
phone.send('hello world'.encode('utf-8'))
#收消息
data=phone.recv(1024)
print(data)
#关机
phone.close()
客户端

2.加上链接循环与通信循环

import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)            #最大挂起的连接数
while True:
    conn,client_addr=phone.accept()       #(套接字链接,客户端的ip和port)
    print(client_addr)
    while True: #通信循环
        try:
            data=conn.recv(1024)            #1024最大的限制
            print('客户端消息:',data)
            if not data:break   #针对Linux系统
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
phone.close()
服务端
import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.connect(('127.0.0.1',8080))
while True:
    msg=input('>>:').strip()
    if not msg: continue
    phone.send(msg.encode('utf-8'))
    data=phone.recv(1024)
    print(data.decode('utf-8'))

phone.close()
客户端

3.实现ssh远程执行命令

import socket,subprocess

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)            #最大挂起的连接数
while True:
    conn,client_addr=phone.accept()       #(套接字链接,客户端的ip和port)
    print(client_addr)
    while True: #通信循环
        try:
            cmd=conn.recv(1024)            #1024最大的限制
            print('客户端消息:',cmd)
            if not cmd:break   #针对Linux系统
            obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            stdout_res=obj.stdout.read()
            stderr_res=obj.stderr.read()
            conn.send(stdout_res+stderr_res)
        except ConnectionResetError:
            break
    conn.close()
phone.close()
服务端
import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.connect(('127.0.0.1',8080))
while True:
    cmd=input('>>:').strip()
    if not cmd: continue
    phone.send(cmd.encode('utf-8'))
    cmd_res=phone.recv(1024)
    print(cmd_res.decode('gbk'))
phone.close()
客户端

三.粘包

 处理粘包1(加上固定长度的报头):

import socket,subprocess,struct

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)            #最大挂起的连接数
while True:
    conn,client_addr=phone.accept()       #(套接字链接,客户端的ip和port)
    print(client_addr)
    while True: #通信循环
        try:
            cmd=conn.recv(1024)            #1024最大的限制
            print('客户端消息:',cmd)
            if not cmd:break   #针对Linux系统
            obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            stdout_res=obj.stdout.read()
            stderr_res=obj.stderr.read()
            #先发报头
            data_size=len(stdout_res)+len(stderr_res)
            conn.send(struct.pack('i',data_size))
            conn.send(stdout_res)
            conn.send(stderr_res)
        except ConnectionResetError:
            break
    conn.close()
phone.close()
服务端
import socket,struct

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.connect(('127.0.0.1',8080))
while True:
    cmd=input('>>:').strip()
    if not cmd: continue
    phone.send(cmd.encode('utf-8'))
    #先收报头
    head_strct=phone.recv(4)
    total_size=struct.unpack('i',head_strct)[0]
    cmd_res=b''
    recv_size=0
    while recv_size<total_size:
        recv_data=phone.recv(1024)
        cmd_res+=recv_data
        recv_size+=len(recv_data)
    print(cmd_res.decode('gbk'))
phone.close()
客户端

 处理粘包2(加上反映数据信息的报头,和报头长度):

import socket,subprocess,struct,json

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)            #最大挂起的连接数
while True:
    conn,client_addr=phone.accept()       #(套接字链接,客户端的ip和port)
    print(client_addr)
    while True: #通信循环
        try:
            cmd=conn.recv(1024)            #1024最大的限制
            print('客户端消息:',cmd)
            if not cmd:break   #针对Linux系统
            obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            stdout_res=obj.stdout.read()
            stderr_res=obj.stderr.read()
            #制作报头
            head_dic={
                'filename':'a.txt',
                'total_size':len(stdout_res)+len(stderr_res),
                'md5':'fiwehfoaejrfanf'
            }
            head_json=json.dumps(head_dic).encode('utf-8')
            #先发报头长度
            conn.send(struct.pack('i',len(head_json)))
            #再发报头
            conn.send(head_json)
            #再发数据
            conn.send(stdout_res)
            conn.send(stderr_res)
        except ConnectionResetError:
            break
    conn.close()
phone.close()
服务端
import socket,struct,json

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)       #tcp协议
phone.connect(('127.0.0.1',8080))
while True:
    cmd=input('>>:').strip()
    if not cmd: continue
    phone.send(cmd.encode('utf-8'))
    #先收报头长度
    struct_res=phone.recv(4)
    head_size=struct.unpack('i',struct_res)[0]
    #先收报头
    head_json=phone.recv(head_size).decode('utf-8')
    head_dic=json.loads(head_json)

    cmd_res=b''
    recv_size=0
    total_size=head_dic['total_size']
    while recv_size<total_size:
        recv_data=phone.recv(1024)
        cmd_res+=recv_data
        recv_size+=len(recv_data)
    print(cmd_res.decode('gbk'))
phone.close()
客户端

四. 基于UDP的套接字

#服务器端
import socket
ip_port=('127.0.0.1',9000)
BUFSIZE=1024
#创建一个服务器的套接字
udp_server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#绑定服务器套接字
udp_server.bind(ip_port)

while True:
    #接收
    msg,addr=udp_server.recvfrom(BUFSIZE)
    print(msg,addr)
    #发送
    udp_server.sendto(msg.upper(),addr)

udp_server.close()
import socket
ip_port=('127.0.0.1',9000)
BUFSIZE=1024
# 创建客户套接字
udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    msg=input('>>: ').strip()
    if not msg:continue
   #发送
    udp_client.sendto(msg.encode('utf-8'),ip_port)
    #接收
    back_msg,addr=udp_client.recvfrom(BUFSIZE)
    print(back_msg.decode('utf-8'),addr)

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Python基础学习参考(五):字符串和编码

下一篇:洗礼灵魂,修炼python(66)--爬虫篇—BeauitifulSoup进阶之“我