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

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

OSI七层模型:

TCP/IP协议:

TCP三次握手:

TCP四次挥手:

TCP通信:

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

socket_server.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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()
socket_client.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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()
socket_client.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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命令并返回结果

socket_server.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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()
socket_client.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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') # 解决粘包问题
#准备发送之前,先发送‘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()
socket_client.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: wanghuafeng 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 #解决粘包问题
#接收消息,其实是为了得到‘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')) 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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:WangHuafeng import socketserver
import subprocess
import json 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) 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") if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('192.168.6.130', 8999), MyServer)
server.serve_forever()
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. 解决TortoiseCVS中文乱码

    解决TortoiseCVS中文乱码必备,解决方法: 第一:卸载和TortoiseCVS安装一起安装的CVSNT. 第二:安装本版本CVSNT. CVSNT下载地址:http://down.51cto. ...

  2. 分布式助手Zookeeper(三)

    分布式助手Zookeeper(三)博客分类: Zookeeper zookeeperapi操作zookeeper 本篇,散仙要介绍一下基于zookeeper的一些API的编程. 在此之前,我们先来熟悉 ...

  3. [Webpack 2] Import a non-ES6 module with Webpack

    When you have a dependency that does not export itself properly, you can use the exports-loader to f ...

  4. textarea文本域宽度和高度(width、height)自己主动适应变化处理

    文章来源:http://www.cnblogs.com/jice/archive/2011/08/07/2130069.html <HTML> <HEAD> <TITLE ...

  5. InnoTop

    是一个系统活动报告,类似于Linux性能工具,它与Linux的top命令相仿,并参考mytop工具而设计. 它专门用后监控InnoDB性能和MySQL服务器.主要用于监控事务,死锁,外键,查询活动,复 ...

  6. IOPS=(Queue Depth)/(IO latency)

    IO 延迟:存储设备的IO延迟 Queue Depth:磁盘控制器所发出的批量指令的最大条数 IOPS:磁盘设备每秒的IO 三者之间的关系:IOPS=(Queue Depth)/(IO latency ...

  7. WPF中DataGrid的ComboBox的简单绑定方式(绝对简单)

    在写次文前先不得不说下网上的其他wpf的DataGrid绑定ComboBox的方式,看了之后真是让人欲仙欲死. 首先告诉你一大堆的模型,一大堆的控件模板,其实或许你紧紧只想知道怎么让combobox怎 ...

  8. WWDC2016 Session笔记 – Xcode 8 Auto Layout新特性

    目录 1.Incrementally Adopting Auto Layout 2.Design and Runtime Constraints 3.NSGridView 4.Layout Feedb ...

  9. javascript进击(九)参考手册

    完整的 Number 对象参考手册 如需可用于 Number 对象的所有属性和方法的完整参考,请访问我们的 Number 对象参考手册. 该参考手册包含每个属性和方法的描述和实例. 完整的 Strin ...

  10. Linux grep用法整理

    grep -i 忽略大小写 grep --color grep -v 反向查找 grep -o 只显示被模式匹配到的字符串