码迷,mamicode.com
首页 > 其他好文 > 详细

09 socket(一)

时间:2016-07-09 00:33:01      阅读:147      评论:0      收藏:0      [点我收藏+]

标签:

1. socket介绍

socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

socket和file的区别:

  • file模块是针对某个指定文件进行【打开】【读写】【关闭】
  • socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

2. Socket流程图

技术分享

3. Socket应用(打电话)

3.1 单进程单次

server代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

# 买手机
s=socket.socket()
# 买手机卡
s.bind(ip_port) #bind(元组)
# 开机
s.listen(5)  #最大等待连接5,第7个连接会报错
#等待电话
conn, addr = s.accept()
#收消息
recv_data = conn.recv(1024)
#发消息
send_data = recv_data.upper()
conn.send(send_data)
# 挂电话
conn.close()

client代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

#买手机
s = socket.socket()
#拨号
s.connect(ip_port)
#发送消息
send_data = input(">>: ").strip()
s.send(bytes(send_data, encoding=‘utf8‘))  #Python3.0 socket发送字节
#收消息
recv_data = s.recv(1024)
print(str(recv_data, encoding="utf8"))
#挂电话
s.close()

实现客户端向服务端单次收发消息,任意一端断开后连接中断

3.2 优化1单进程循环

优化内容:可多次收发消息,过滤回车、空格输入

server代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

# 买手机
s=socket.socket()
# 买手机卡
s.bind(ip_port) #bind(元组)
# 开机
s.listen(5)  #最大等待连接5
#等待电话
conn, addr = s.accept()
while True:
    try:
        #收消息
        recv_data = conn.recv(1024)
        if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出

        #发消息
        send_data = recv_data.upper()
        conn.send(send_data)
    except Exception:
        break

# 挂电话
conn.close() 

client代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

#买手机
s = socket.socket()
#拨号
s.connect(ip_port)
while True:
    #发送消息
    send_data = input(">>: ").strip()
    if len(send_data) == 0:continue  #判断是否为空格或回车,继续执行
    s.send(bytes(send_data, encoding=‘utf8‘))  #Python3.0 socket发送字节
    if send_data == "exit":break #输入exit退出
    #收消息
    recv_data = s.recv(1024)
    print(str(recv_data, encoding="utf8"))
#挂电话
s.close()

3.3 优化2解决阻塞

server代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

# 买手机
s=socket.socket()
# 买手机卡
s.bind(ip_port) #bind(元组)
# 开机
s.listen(5)  #最大等待连接数,超出时不可连接
while True: 
#等待电话
    conn, addr = s.accept()
    while True:
        try:
            recv_data = conn.recv(1024)
            if len(recv_data) == 0:break
            if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出

            #发消息
            send_data = recv_data.upper()

            print(send_data)
            conn.send(send_data)
        except Exception:
            break

    # 挂电话
    conn.close()

client代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

#买手机
s = socket.socket()
#拨号
s.connect(ip_port)
while True:
    #发送消息
    send_data = input(">>: ").strip()
    if len(send_data) == 0:continue  #判断是否为空格或回车,继续执行
    s.send(bytes(send_data, encoding=‘utf8‘))  #Python3.0 socket发送字节
    if send_data == "exit":break #输入exit退出
    #收消息
    recv_data = s.recv(1024)
    print(str(recv_data, encoding="utf8"))
#挂电话
s.close()

4. Socket应用(SSH)

4.1 模拟ssh

server代码

import socket
import subprocess

ip_port = (‘127.0.0.1‘, 9999)
s = socket.socket()
s.bind(ip_port) #bind(元组)
s.listen(5)  #最大等待连接数,超出时不可连接

while True:
    conn, addr = s.accept()
    while True:
        try:
            recv_data = conn.recv(1024)
            if len(recv_data) == 0:break
            if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出

            #发消息
            p=subprocess.Popen(str(recv_data, encoding="utf8"), shell=True, stdout=subprocess.PIPE)
            res = p.stdout.read()
            if len(res) == 0:
                send_data = "cmd error"
            else:
                send_data = str(res, encoding=‘gbk‘)

            print(send_data)
            conn.send(bytes(send_data, encoding="utf8"))
        except Exception:
            break

    conn.close()

client代码

import socket
ip_port = (‘127.0.0.1‘, 9999)

s = socket.socket()
s.connect(ip_port)
while True:
    #命令
    send_data = input(">>: ").strip()
    if len(send_data) == 0:continue  #判断是否为空格或回车,继续执行
    s.send(bytes(send_data, encoding=‘utf8‘))  #Python3.0 socket发送字节
    if send_data == "exit":break #输入exit退出
    #接收返回信息
    recv_data = s.recv(1024)
    print(str(recv_data, encoding="utf8"))

s.close()

4.2 解决粘包

问题:接收发送消息1024字节,超出时出现粘包

思路:服务端告知客户端数据大小,客户端确认后开始接收

server代码

port = (‘127.0.0.1‘, 999)  #定义元祖

s = socket.socket()  #绑定协议,生成套接字
s.bind(ip_port) #绑定IP+协议+端口,用来唯一标识一个进程,ip_prot必须是元祖格式

s.listen(5)  #定义最大可以挂起链接数

while True:  #用来重复接收新的链接
    conn, addr = s.accept()  #接收客户端的链接请求,返回conn(相当于一个特定的链接),addr是客户端的IP+prot
    while True:  #用于基于一个链接重复收发消息
        try:  #捕捉客户端异常关闭(ctrl+c)
            recv_data = conn.recv(1024)  #收消息,阻塞
            if len(recv_data) == 0:break  #客户端如果退出,服务端将收到空消息,退出

            #发消息
            p=subprocess.Popen(str(recv_data, encoding="utf8"), shell=True, stdout=subprocess.PIPE)  #执行系统命令,windows平台命令的标准输出是gbk编码,需要转换
            res = p.stdout.read()  #获取标准输出
            if len(res) == 0:  #执行错误命令,标准输出为空
                send_data = "cmd error"
            else:
                send_data = str(res, encoding=‘gbk‘)  #命令执行OK,字节gbk---->str--->utf8

            send_data=bytes(send_data, encoding=‘utf8‘)  #str--->utf8

            #解决粘包问题
            ready_tag = "Ready|%s" %len(send_data)  #
            conn.send(bytes(ready_tag, encoding=‘utf8‘)) #发送长度
            feedback = conn.recv(1024) #接收确认信息
            feedback = str(feedback,encoding="utf8")  #接收客户端确认消息

            if feedback.startswith(‘Start‘):
                conn.send(send_data)  #发送命令的执行结果
        except Exception:
            break


    # 挂电话
    conn.close()

client代码

import socket
ip_port = (‘127.0.0.1‘, 999)

s = socket.socket()
s.connect(ip_port)  #链接服务端,如果服务端已经存在一个好的连接,那么挂起
while True:    #基于connect建立的连接来循环发送消息
    send_data = input(">>: ").strip()
    if send_data == "exit":break #输入exit退出
    if len(send_data) == 0:continue  #判断是否为空格或回车,继续执行
    s.send(bytes(send_data, encoding=‘utf8‘))  #Python3.0 socket发送字节

    #解决粘包
    ready_tag = s.recv(1024)  #收取带数据长度的字节:Ready|9998
    ready_tag = str(ready_tag,encoding=‘utf8‘)
    if ready_tag.startswith(‘Ready‘): #ready|9998
        msg_size = int(ready_tag.split("|")[-1])  #获取待接收数据长度
    start_tag = ‘Start‘
    s.send(bytes(start_tag,encoding=‘utf8‘))  #发送确认信息

    #基于已经收到的待接收数据长度,循环接收数据
    recv_size = 0
    recv_msg = b‘‘
    while recv_size < msg_size:
        recv_data = s.recv(1024)
        recv_msg += recv_data
        recv_size += len(recv_data)
        print(‘MSG SIZE %s RECE SIZE %s‘ %(msg_size, recv_size))

    print(str(recv_msg, encoding="utf8"))

s.close() 

5. Socket应用(并发)

server代码

import socketserver

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        self.request.sendall(bytes(‘欢迎致电10086,请输入1xxx,0转人工服务.‘, encoding="utf8"))
        while True:
            data = self.request.recv(1024)
            print("--->", len(data))
            if len(data) == 0:break
            print("[%s] says:%s" %(self.client_address, data.decode()))
            self.request.sendall(data.upper())


if __name__ == ‘__main__‘:
    server = socketserver.ThreadingTCPServer((‘127.0.0.1‘, 8009), MyServer)
    server.serve_forever()

client代码

import socket
ip_port=(‘127.0.0.1‘,8009)

s=socket.socket()

s.connect(ip_port)
#发送消息
welcome_msg = s.recv(1024) #接收欢迎信息
print("from server:",welcome_msg.decode())
while True:
    send_data=input(">>: ").strip()
    if len(send_data) == 0:continue
    s.send(bytes(send_data,encoding=‘utf8‘))

    #收消息
    recv_data=s.recv(1024)
    print(str(recv_data,encoding=‘utf8‘))

s.close()

 

 

 

 

 

 

 

import socketserver

class MyServer(socketserver.BaseRequestHandler):
   
def handle(self):
       
self.request.sendall(bytes(欢迎致电10086,请输入1xxx,0转人工服务.‘, encoding="utf8"))
       
while True:
           
data = self.request.recv(1024)
           
print("--->", len(data))
           
if len(data) == 0:break
           
print("[%s] says:%s" %(self.client_address, data.decode()))
           
self.request.sendall(data.upper())


if __name__ == ‘__main__‘:
   
server = socketserver.ThreadingTCPServer((‘127.0.0.1‘, 8009), MyServer)
    server.serve_forever()

client

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

import socket
ip_port
=(‘127.0.0.1‘,8009)
#买手机
s=socket.socket()
#拨号
s.connect(ip_port)
#发送消息
welcome_msg = s.recv(1024) #接收欢迎信息
print("from server:",welcome_msg.decode())
while True:
   
send_data=input(">>: ").strip()
   
if len(send_data) == 0:continue
   
s.send(bytes(send_data,encoding=‘utf8‘))

   
#收消息
   
recv_data=s.recv(1024)
   
print(str(recv_data,encoding=‘utf8‘))
   
#挂电话
s.close()

09 socket(一)

标签:

原文地址:http://www.cnblogs.com/liangdalong/p/5654963.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!