内网版交互日记系统

写在前面

听了大妈2wd4的公开课挺有感触的,感想稍后补上。

简而言之,准备在这次任务上进行如下改进

  • 用最小成本解决问题
  • 先记录思考和计划,再开始码代码
  • 把姿态放低,记录自己的困惑和情绪
  • 清晰地记录5W1H

背景

  • 系统:OS X 10.11
  • python版本:Python 2.7.10
  • 编辑器:Sublime Text 3
  • 终端:iterm2
  • shell:zsh

任务要求

在上周开发基础上, 完成 极简交互式笔记的网络版本 需求如下:

  • 每次运行时合理的打印出过往的所有笔记
    • 一次接收输入一行笔记
  • 在服务端保存为文件:
  • 在所有访问的客户端可以获得历史笔记
  • 支持多个客户端同时进行笔记记录

任务分析

先仔细看芝麻星3w卡片的正反面,提取出一些关键提示

★3w Net

  • UDP 协议
  • 网络数据传输
  • C/S 架构实现
  • 网络应用调试技巧
  • (网络抓包分析)
  • MyDailyNet 私人记事本内网CLI版


参考:

提取关键词

  • C/S 架构
  • UDP
  • socket (好几个卡片背后都指向它)

我在深挖官方文档前,喜欢先google一下关键词,然后简单地浏览一下,好在脑中对这个关键词形成大致印象,知道网上关于这个关键词都有怎么样的文章。

搜索了这三个关键词之后,形成的印象是

  • C/S:应该就是指的client和server之间的交互
  • UDP:没太看明白
  • socket:python的一个库,跟网络连接有关

然后去看大妈的演示demo,公开课大妈演示3w任务demo的时候,我的页面黑屏了,切备用线路恢复过来的时候,大妈也差不多演示完了囧,还好这些演示都能在邮件里找到 益rz。

在demo中观察到的点:

  • 虽然都是运行main.py
    • 但猜测server上调用了md4srv.py
    • client上调用了md2client.py
  • usage里提示参数可以输入s或者c
    • 那应该server上和client上的main.py是一样的
    • 使用参数解析
      • 如果是's',调用md4srv.py
      • 如果是'c',调用md2client.py
  • log文件只保存在server上

总结一下要做的任务:

  • 写一个本地的client脚本
  • 写一个server脚本
  • 将server脚本部署到服务器上

要怎么部署到服务器上,没多大概念,网上搜了下也没太理清楚。

算了,先stay calm & go to sleep

2015-10-29 end

2015-10-30

虽然分析了任务,但其实还是没太想通,没想出详细可执行的计划。

正好前几天coursera上有一门《使用 Python 访问网络数据》开课了,先去看看。

第一部分讲正则,跳过。

第二部分讲network,相关的,看下吧。

三个视频加起来半个多小时吧,看完之后了解了

  • HTTP协议,如何发送GET请求
  • socket:就像电话听筒,两个socket连接之后可以传输信息

还练习了一段简单的代码

import socket

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立一个socket对象,类似于f=open(...)建立file对象
mysock.connect(('www.py4inf.com', 80)) #将socket连接到某个host和port
mysock.send('GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n') #发送GET请求

while True:
    data = mysock.recv(512) # 一次接受512字节的信息
    if ( len(data) < 1 ) :
        break
    print data;

mysock.close()

看完这几个MOOC视频之后就想明白了,这周任务的关键是socket

然后网上再去搜索socket,在这篇文章里看到了一句运行程序时,启动两个终端,然后每个终端运行一个程序就可以了

啥? 服务端的代码不需要部署到服务器,只需要终端运行就行了?

启动两个终端试了一下文章里的代码,确实可以运行。突然想起芝麻星卡片里写着MyDailyNet 私人记事本内网CLI版,既然说了内网,那应该就是不用部署到服务器的。

上面文章的示例代码是

server端

import socket
port=8081
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#从指定的端口,从任何发送者,接收UDP数据
s.bind(('',port))
print('正在等待接入...')
while True:
    #接收一个数据
    data,addr=s.recvfrom(1024)
    print 'Received:',data,'from',addr

client端

import socket
port=8081
host='localhost'
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto(b'hello,this is a test info !',(host,port))

在测试上面代码时,发现socket.socket()里第二个参数是socket.SOCK_DGRAM,跟我之前coursera上例子里用的socket.SOCK_STREAM不太一样,查了一下发现前者对应UDP协议,后者对应HTTP协议。ok,大妈的任务里提示最好用UDP,那ok,我先主要关注UDP相关的。

此外,从上面代码学到了怎么从client发送信息给server,那我就可以先通过client发送日记信息给server,然后server接收到信息之后把信息写入log文件里。

改写、测试、成功。具体代码记录在代码repo的git历史里。

那之后需要做的就是怎么让server端发回信息给client端。

之后再用python socket UDP进行搜索,搜到了这篇文章,里面示例了echo server和echo client,就是从socket收到了什么信息,就把同样的信息传回去。

Echo Server

import socket
import sys

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Bind the socket to the port
server_address = ('localhost', 10000)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)

while True:
    print >>sys.stderr, '\nwaiting to receive message'
    data, address = sock.recvfrom(4096)

    print >>sys.stderr, 'received %s bytes from %s' % (len(data), address)
    print >>sys.stderr, data

    if data:
        sent = sock.sendto(data, address)
        print >>sys.stderr, 'sent %s bytes back to %s' % (sent, address)

Echo Client

import socket
import sys

# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

server_address = ('localhost', 10000)
message = 'This is the message.  It will be repeated.'

try:

    # Send data
    print >>sys.stderr, 'sending "%s"' % message
    sent = sock.sendto(message, server_address)

    # Receive response
    print >>sys.stderr, 'waiting to receive'
    data, server = sock.recvfrom(4096)
    print >>sys.stderr, 'received "%s"' % data

finally:
    print >>sys.stderr, 'closing socket'
    sock.close()

在这个例子的基础上进行改写,就能实现从server端将日记信息返回给client端。

但是server端一直是处于监听状态,要怎么主动把日记信息发到client端呢。

  • client连接上server之后,是否改变了server的一些变量呢,根据这个变量写判断语句可以让client连上之后server就将日记信息发给它
  • client先发一个特定信息给server,server判断出这是特定信息之后就把日记历史发给client

想了一下,后者更容易实现,那就用后面这个方法吧,那接下来的问题就是,怎么选择特定信息呢。

  • 尝试空信息''
    • 后来想想,用户可能会想输入空行,这样行不通
  • q吧,用户输入q就退出了client端的程序,所以在用户输入过程中client不会把q传到server端
    • ok,那就让client已连接上就发个q给server,然后接受和打印server端传来的日记历史信息
    • 然后server收到q就把日记历史信息传给client

码好代码之后,测试,基本完成任务。

那就先把任务提交了吧,之后再去深入学习官方文档。

  • 开始写README文档
  • 录一个演示视频,好让别人看到实现的效果
    • 之前是用七牛在做图床,测试下是否能用它储存视频文件,成功。
  • 搜索怎么在Markdown中引用视频

2015-10-31

现在想的的问题:

  • 传输信息过大怎么办,我现在设置的是能接受4096个字节,超了怎么办?
  • 多个客户端同时发送信息,服务端该怎么处理
  • 如何根据客户端信息进行单独的信息处理和传输

暂时没深入思考这些问题,先给自己放个小假,学会numpy。

油管上看了一个视频,介绍websockets的,里面还提到了Wireshark这个工具。

下载安装了Wireshark,准备研究抓包。

使用截屏

screenshot

学习资源:

有时间的话再研究下websockets

小插曲:
打开server端程序之后,打开client端程序,这时server端报错,看了一下,发现是我把log文件删了,然后server端程序里没写初始化log文件的功能,遂补上。

2015-11-2

找到了一个mooc视频,讲解了一些socket知识,里面对client和server中socket的行为讲解的很清楚。

                client ------------ server
                    |                   |----1: socket
       1: socket----|                   |----2: bind
                    |                   |----3: listen
     5: connect*----|-----connect-------|----4: accept*
                    |                   |
         7: send----|-----request-------|----6: recv*
                    |                   |
        8: recv*----|-----reply---------|----9: send
                    |                   |
       10: close----|----disconnect-----|----10: close

*星号的代表程序在这个步骤会停止下来,直到等到对方的信息再继续

想了想根据不同客户端进行回复的问题

  • 虽然server和client连的是同一个host和port,但每次具体连接都用的是不同的端口点,所以用address来定制回复信息不太行得通。
  • 有一个比较简单的解决办法,就是client先让用户报上自己名字,然后发给server,然后server根据姓名来进行回复
    • server里能储存一个有效用户姓名的列表

results matching ""

    No results matching ""