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. response对象详解

    (响应 javax.servlet.http.HttpServletResponse) 方法名 说明 addCookie 添加一个Cookie对象 addHeader 添加Http文件指定名字头信息 ...

  2. qt学习笔记(五) QGraphicsPixmapItem与QGraphicsScene的编程实例 图标拖动渐变效果

    应大家的要求,还是把完整的project文件贴出来,大家省点事:http://www.kuaipan.cn/file/id_48923272389086450.htm 先看看执行效果,我用的群创7寸屏 ...

  3. Java NIO与IO的差别和比較

    导读 J2SE1.4以上版本号中公布了全新的I/O类库.本文将通过一些实例来简介NIO库提供的一些新特性:非堵塞I/O,字符转换,缓冲以及通道. 一. 介绍NIO NIO包(java.nio.*)引入 ...

  4. C# - 系统类 - Object类

    Object类 ns:System 此类是所有.NET Framework中的类的基类 Type类就派生自Object类 C#提供了object关键字来表示一个类实例的类型 而无需使用Object作为 ...

  5. Map的遍历方式

    public class Mapper { public static void main(String[] args) {  Map<String, String> map = new ...

  6. uedoc 源码解析

    思路分析 node 包使用 1. JSON5 2. art-template 3.

  7. c语言,strcspn,在串中查找第一个给定字符集内容的段

    函数名: strcspn 功 能: 在串中查找第一个给定字符集内容的段 用 法: int strcspn(char *str1, char *str2); 程序例: #include <stdi ...

  8. C# ado.net 使用 row_number over() 简单的分页示例

    /// <summary> /// 获取Paging列表 /// </summary> public List<HousesAgentEntity> GetPage ...

  9. Oracle之Merge用法

    Merge用来从一个表中选择一些数据更新或者插入到另一个表中.而最终是用更新还是用插入的方式取决于该语句中的条件. 下面我们简单的举一个例子: SQL)) 表已创建. SQL)) 表已创建. SQL, ...

  10. 解构控制反转(IoC)和依赖注入(DI)

    1.控制反转 控制反转(Inversion of Control,IoC),简言之就是代码的控制器交由系统控制,而不是在代码内部,通过IoC,消除组件或者模块间的直接依赖,使得软件系统的开发更具柔性和 ...