OSI(Open System Interconnect),即开放式系统互联。

ISO(International Standards Organization)国际标准化组织

OSI七层模型:

TCP/IP协议:

TCP三次握手:

TCP四次挥手:

TCP通信:

模拟简单的客户端-服务器TCP通信

socket_server.py

  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    s = socket.socket()
    #买手机卡,bind中的参数为元祖
    s.bind(ip_port)
    #开机
    s.listen(5)
    #等待电话,conn为通信链路
    conn, addr = s.accept()
    #收消息,1024--代表字节
    recv_data = conn.recv(1024)
    print(str(recv_data, encoding='utf-8'))
    #发消息
    send_data = recv_data.upper()
    conn.send(send_data)
    #挂电话
    conn.close()
  1. socket_client.py
  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    sk = socket.socket()
    #拨号
    sk.connect(ip_port)
    #发消息
    send_data = input(">>>: ").strip()
    sk.send(bytes(send_data, encoding='utf-8'))
    #收消息
    recv_data = sk.recv(1024)
    print(recv_data)
    #挂电话
    sk.close()

UDP通信

# 服务端

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)

sk.bind(ip_port)

while True:

    data,(host,port) = sk.recvfrom(1024)

    print(data,host,port)

    sk.sendto(bytes('ok', encoding='utf-8'), (host,port))

#客户端

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)

while True:

    inp = input('数据:').strip()

    if inp == 'exit':

        break

    sk.sendto(bytes(inp, encoding='utf-8'),ip_port)

    data = sk.recvfrom(1024)

    print(data)

sk.close()

更多功能

sk.bind(address)

s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。

      backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5

      这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)

连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close()

关闭套接字

sk.recv(bufsize[,flag])

接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag])

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

      内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout)

设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()

返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()

套接字的文件描述符

循环发送消息

socket_server.py

  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    s = socket.socket()
    #买手机卡,bind中的参数为元祖
    s.bind(ip_port)
    #开机
    s.listen(5)
    #等待电话,conn为通信链路
    conn, addr = s.accept()
    while True:
    try:
    #收消息,1024--代表字节
    recv_data = conn.recv(1024)
    print(str(recv_data, encoding='utf-8'))
    if str(recv_data, encoding='utf-8') == 'exit':break
    #发消息
    send_data = recv_data.upper()
    conn.send(send_data)
    except Exception:
    break
    #挂电话
    conn.close()
  1. socket_client.py
  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    sk = socket.socket()
    #拨号
    sk.connect(ip_port)
    #发消息
    while True:
    send_data = input(">>>: ").strip()
    if len(send_data) == 0:continue
    sk.send(bytes(send_data, encoding='utf-8'))
    if send_data == 'exit':break
    #收消息
    recv_data = sk.recv(1024)
    print(recv_data)
    #挂电话
    sk.close()

发送windows命令并返回结果

  1. socket_server.py
  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    import subprocess
    ip_port = ('127.0.0.1', 9999)
    #买手机
    s = socket.socket()
    #买手机卡,bind中的参数为元祖
    s.bind(ip_port)
    #开机
    s.listen(5)
    #等待电话,conn为通信链路
    #重复接收多个连接
    while True:
    conn, addr = s.accept()
    while True:
    try:
    #收消息,1024--代表字节
    recv_data = conn.recv(1024)
    print(str(recv_data, encoding='utf8'))
    if str(recv_data, encoding='utf8') == 'exit':break
    #发消息
    # 在Windows服务器获取命令
    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()
  1. socket_client.py
  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    sk = socket.socket()
    #拨号
    sk.connect(ip_port)
    #发消息
    while True:
    send_data = input(">>>: ").strip()
    if len(send_data) == 0:continue
    sk.send(bytes(send_data, encoding='utf8'))
    if send_data == 'exit':break
    #收消息
    recv_data = sk.recv(1024)
    print(str(recv_data, encoding='utf8'))
    #挂电话
    sk.close()

解决粘包

socket_server.py

  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    import subprocess #导入执行命令模块
    ip_port = ('127.0.0.1', 9999) #定义IP和端口的元组
    #买手机
    s = socket.socket() #绑定协议,生成套接字
    #买手机卡,bind中的参数为元祖
    s.bind(ip_port) #绑定IP+协议+端口,用来唯一标识一个进程,ip_port必须是元组格式
    #开机
    s.listen(5) #定义最大可以挂起链接数
    #等待电话,conn为通信链路
    #重复接收多个连接
    while True: #用来重复接收新的链接
    conn, addr = s.accept() #接收客户端链接请求,返回conn(相当于通信信道,addr是客户端IP+Port)
    while True: #用于基于一个链接重复收发消息
    try: #捕捉客户端异常关闭(ctrl+c)
    #收消息,1024--代表字节
    recv_data = conn.recv(1024) #收消息,阻塞
    if len(recv_data) == 0:break #客户端如果退出,服务端将收到空消息,退出
    if str(recv_data, encoding='utf8') == 'exit':break #客户端发送exit消息,表示退出,服务端将退出
    #发消息
    # 在Windows服务器获取命令,并执行命令,Windows平台标准输出是gbk编码需要转换
    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') #执行ok,字符编码转换,gbk-->str-->utf8字节
    send_data = bytes(send_data, encoding='utf8')
  4.  
  5. # 解决粘包问题
    #准备发送之前,先发送‘Ready|内容长度’
    ready_tag = 'Ready|%s' %len(send_data)
    conn.send(bytes(ready_tag, encoding='utf8'))
    #得到客户端返回‘Start’表示客户端已经接收到‘Ready|内容长度’
    feedback = conn.recv(1024) #Start
    #接收的内容为bytes类型,需要转换为str类型
    feedback = str(feedback, encoding='utf8')
    if feedback.startswith('Start'):
    conn.send(send_data) #发送命令执行结果
    except Exception:
    break
    #挂电话
    conn.close()
  1. socket_client.py
  1. #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # Author: wanghuafeng
  2.  
  3. import socket
    ip_port = ('127.0.0.1', 9999)
    #买手机
    sk = socket.socket()
    #拨号
    sk.connect(ip_port) #连接服务端,若服务端有一个已经存在的链接,则连接挂起
    #发消息
    while True: #基于connect建立的链接来循环发送消息
    send_data = input(">>>: ").strip()
    if len(send_data) == 0:continue
    sk.send(bytes(send_data, encoding='utf8'))
    if send_data == 'exit':break
  4.  
  5. #解决粘包问题
    #接收消息,其实是为了得到‘Ready|内容长度’
    ready_tag = sk.recv(1024)
    ready_tag = str(ready_tag, encoding='utf8')
    #收到‘Ready|内容长度’
    if ready_tag.startswith("Ready"):
    #获取待接收数据的长度
    msg_size = int(ready_tag.split('|')[-1])
    #准备一个‘Start’
    start_tag = 'Start'
    #发送一个‘Start’消息,通知服务端可以发送消息了
    sk.send(bytes(start_tag, encoding='utf8'))
  6.  
  7. recv_size = 0
    recv_msg = b''
    while recv_size < msg_size:
    recv_data = sk.recv(1024)
    recv_msg += recv_data
    recv_size += len(recv_data)
    print('MSG SIZE %s RECV SIZE %s' % (msg_size, recv_size))
    print(str(recv_msg, encoding='utf8'))
    #挂电话
    sk.close()

socketserver解决粘包问题

import socketserver

import subprocess

class Myserver(socketserver.BaseRequestHandler):

    def handle(self):

        while True:

            conn=self.request

            conn.sendall(bytes("欢迎登录","utf8"))

            while True:

                client_bytes=conn.recv(1024)

                if not client_bytes:break

                client_str=str(client_bytes,"utf8")

                print(client_str)

                command=client_str

                result_str=subprocess.getoutput(command)

                result_bytes = bytes(result_str,encoding='utf8')

                info_str="info|%d"%len(result_bytes)

                conn.sendall(bytes(info_str,"utf8"))

                # conn.recv(1024)

                conn.sendall(result_bytes)

            conn.close()

if __name__=="__main__":

    server=socketserver.ThreadingTCPServer(("127.0.0.1",9998),Myserver)

    server.serve_forever()

#####################################client

import socket

ip_port=("127.0.0.1",9998)

sk=socket.socket()

sk.connect(ip_port)

print("客户端启动...")

print(str(sk.recv(1024),"utf8"))

while True:

    inp=input("please input:").strip()

    sk.sendall(bytes(inp,"utf8"))

    basic_info_bytes=sk.recv(1024)

    print(str(basic_info_bytes,"utf8"))

    # sk.send(bytes('ok','utf8'))

    result_length=int(str(basic_info_bytes,"utf8").split("|")[1])

    print(result_length)

    has_received=0

    content_bytes=bytes()

    while has_received<result_length:

        fetch_bytes=sk.recv(1024)

        has_received+=len(fetch_bytes)

        content_bytes+=fetch_bytes

    cmd_result=str(content_bytes,"utf8")

    print(cmd_result)

sk.close()

实现简单FTP功能

ftp_server.py

  1. #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    #Author:WangHuafeng
  2.  
  3. import socketserver
    import subprocess
    import json
  4.  
  5. class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
    self.request.sendall(bytes("欢迎使用Python Server!", encoding='utf-8'))
    while True:
    data = self.request.recv(1024)
    if len(data) == 0:break
    print('data', data)
    print("[%s] says:%s" % (self.client_address, data.decode()))
    task_data = json.loads(data.decode())
    task_action = task_data.get('action')
    if hasattr(self, 'task_%s' % task_action):
    func = getattr(self, 'task_%s' % task_action)
    func(task_data)
    else:
    print('task action is not supported', task_action)
  6.  
  7. def task_put(self, *args, *kwargs):
    print("---put", args, kwargs)
    filesize = args[0].get('file_size')
    filename = args[0].get('filename')
    server_response = {'status':200}
    self.request.send(bytes(json.dumps(server_response), encoding='utf-8'))
    recv_size = 0
    with open(filename, 'wb') as f:
    while recv_size < filesize:
    data = self.request.recv(4096)
    f.write(data)
    recv_size += len(data)
    print("file recv sucess")
  8.  
  9. if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('192.168.6.130', 8999), MyServer)
    server.serve_forever()
  1. ftp_client.py

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# Author: wanghuafeng

import socket

import os, json

ip_port = ('192.168.6.130', 8999)

sk = socket.socket()

sk.connect(ip_port)

welcome_msg = sk.recv(1024)

while True:

    send_data = input(">>>: ").strip()

    if len(send_data) == 0:continue

    cmd_list = send_data.split()

    if len(cmd_list) < 2:continue   #ftp命令put /usr/bin/file.txt

    task_type = cmd_list[0]

    if task_type == 'put':

        abs_filepath = cmd_list[1]

        if os.path.isfile(abs_filepath):

            #MD5,留着

            file_size = os.stat(abs_filepath).st_size

            file_name = abs_filepath.split('\\')[-1]

            print('file:%s size:%s' % (abs_filepath, file_size))

            msg_data = {'action':'put', 'filename':file_name, 'file_size':file_size}

            sk.send(bytes(json.dumps(msg_data), encoding='utf-8'))

            server_confirmation_msg = sk.recv(1024)

            confirm_data = json.loads(server_confirmation_msg.decode())

            if confirm_data['status'] == 200:

                print('start sending file', file_name)

                with open(abs_filepath, 'rb') as f:

                    for line in f:

                        sk.send(line)

                    print("send file done")

        else:

            print("\033[31;1mfile [%s] is not exist\033[0m" % abs_filepath)

    else:

        print("doesn't support task type", task_type)

        continue

    #sk.send(bytes(send_data, encoding='utf8'))

    recv_data = sk.recv(1024)

    print(str(recv_data, encoding='utf-8'))

sk.close()

Day9 网络编程的更多相关文章

  1. 第九章:Python の 网络编程基础(一)

    本課主題 何为TCP/IP协议 初认识什么是网络编程 网络编程中的 "粘包" 自定义 MySocket 类 本周作业 何为TCP/IP 协议 TCP/IP协议是主机接入互网以及接入 ...

  2. Python基础-week07 Socket网络编程

    一 客户端/服务器架构 1.定义 又称为C/S架构,S 指的是Server(服务端软件),C指的是Client(客户端软件) 本章的中点就是教大写写一个c/s架构的软件,实现服务端软件和客户端软件基于 ...

  3. 猫哥网络编程系列:HTTP PEM 万能调试法

    注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...

  4. python select网络编程详细介绍

    刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...

  5. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  6. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

  7. 浅谈C#网络编程(一)

    阅读目录: 基础 Socket编程 多线程并发 阻塞式同步IO 基础 在现今软件开发中,网络编程是非常重要的一部分,本文简要介绍下网络编程的概念和实践. Socket是一种网络编程接口,它是对传输层T ...

  8. C++11网络编程

    Handy是一个简洁优雅的C++11网络库,适用于linux与Mac平台.十行代码即可完成一个完整的网络服务器. 下面是echo服务器的代码: #include <handy/handy.h&g ...

  9. Java - 网络编程

    Java的网络编程学习,关于计算机基础的学习参考:计算机网络基础学习 - sqh.     参考:  

随机推荐

  1. easyui valid

    /** * 包含easyui的扩展和常用的方法 * * @author * * @version 20120806 */ var wjc = $.extend({}, wjc);/* 定义全局对象,类 ...

  2. 适合高级Java程序员看的12本书

    1.Thinking in Java 2.Head First Java 3.Java in a Nutshell 4.The elements of Java style 5.Effective J ...

  3. UVA 110 Meta-Loopless Sorts(输出挺麻烦的。。。)

     Meta-Loopless Sorts  Background Sorting holds an important place in computer science. Analyzing and ...

  4. TOMCAT 集群之 PERSISTENT SESSION

    tomcat的session保存在数据库中,不是很复杂,写下来供大家参考. 准备工作: 两架Ubuntu Server 12.04 64位,确定两级服务器可以互相ping的通并属于同一个网段 安装jd ...

  5. [置顶] [VS2010]逸雨清风 永久稳定音乐外链生成软件V0.1

    音乐外链说明:现在的很多网站都有用到外链,特别是音乐外链,在博客.空间里设作背景音乐.网上也有很多上传外链的网站,不过都不稳定而且有容量限制,而且似乎所有网站其实都是用的同一个源码组件,都是链接到Ra ...

  6. javascript默认中文(汉字/标点)长度均为1的解决

    javascript默认中文(汉字/标点)长度均为1 与后台(java)不一致, function calculate(str) { //var str="你好,哈哈哈000111lll&q ...

  7. systemtap 列出所有linux 内核模块与相关函数0

    diskiohttp://blog.163.com/digoal%40126/blog/static/16387704020131015105532435/ [root@localhost linux ...

  8. 无法从“object”转换为“string”

    就我在项目中遇到的问题,和大家分享一下“无法从“object”转换为“string” 在把我出错的代码复制上来,  Guid userid = new Guid(Membership.GetUser( ...

  9. Android App用MulticastSocket监听组播,为什么连接到不同路由、在不同手机上跑,有的能收到有的收不到

    ---------------------------!! 转载请注明出处 !!-----------------------   一个项目,利用wifi组播在局域网内发现设备.却发现在有的路由器上能 ...

  10. C# Mutex对象的使用

    C# Mutex对象的使用 C#语言有很多值得学习的地方,这里我们主要介绍C# Mutex对象,包括介绍控制好多个线程相互之间的联系等方面. 如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要 ...