1. 目的及意义
1) 网络通信
第二次机器革命潮起时期,物联网、云计算、大数据如火如荼,网络通信技术是基础;
网络通信应用很多,不仅局限于通信,与其他技术结合可以实现很多有趣、有用的应用;特别是WiFi,这个既有的不需要新建设的、逐渐普及的、有很大潜力的技术,仅举几例:
WiFi时代如何通信 网络电话应用深度思考
http://www.kejixun.com/article/201404/34525.html
WiFi电话一定程度上替代普通电话;
卫星定位技术获取位置,通过通信技术将位置信息传可以实现目标位置监控,目前已有老人、小孩、物品防丢失的商用产品;
麻省理工新技术:借WiFi信号“透视”墙体
http://tech.sina.com.cn/t/2013-06-28/11418489359.shtml
通过特殊编码监测发射和接收信号特征实现目标特性识别;
麻省理工学院 上网的WiFi也能知道你健不健康
http://www.39yst.com/xinwen/20150427/261462.shtml
通过特殊编码监测发射和接收信号特征实现人体状态监测;
2) socket
在众多网络编程方法中,选择底层socket灵活、高效,同时适用于PC/laptop/手机,有线/无线,Windows/linux等各种平台;
3) 编程工具/平台
计算机端使用Python,手机端使用Android/Python。
编程工具配置和使用占了初学者很多精力,另文详述?
4) 定位
从底层开始开发一个完整的应用需要大量的知识、精力,本文实现socket了解、底层基础编程及其模块化以便后续开发,简单地聊天应用以验证和拓展底层基础编程,作为网络通信技术一个基础尝试和后续开发的基础。
2. Android/Python Socket编程基础
另文细述
3. 设计及实现
usr_info_stat数据结构:
name – passwd – stat(login/logout)
命令结构:
#[ type]#[param1]#[param2]
login [name] [passwd]
logout [name] [passwd]
msg [from] [to ]
细节信息在代码注释中已经清楚标明。
Python程序chip_udp_server.py/chip_udp_client.py可以运行在PC/laptop的activePython和Android的Qpython;
Java程序可以在Android以App形式运行;
Python Server端程序:
#!/usr/bin/env python
# =============================================================================
# Copy Rights @Chip, All Rights Reserved
#
# File: chip_udp_server.py
# Description:
# udp server program
# HOWTORUN:
# just start it
# V0.1: Initial Version
# Chip,2015/6/10
# V0.2: Add server account.
# Chip, 2015/6/13
# V1.0: add ip/port setting
# Chip,2015/6/21
# ToDo: 1. printv for all kinds of string.
# 2. msg_proc, reply/resend. - done
# 3. multi user
# 4. bind ip to usr
# 5. free receive/send
# 6. Any IP address
# 7. Android
#
# =============================================================================
# -----------------------------------------------------------------------------
# 1. start/import
# -----------------------------------------------------------------------------
print('1. chip_udp_server.py start/import','\n');
import sys,socket,time
# -----------------------------------------------------------------------------
# 2. data structure
# -----------------------------------------------------------------------------
print('2. data structure','\n');
# FIXME: better data structure?
usr_name = ['John','Tom','Ben','Server']
usr_passwd = ['J123','T123','B123','S123']
usr_stat = ['logout','logout','logout','logout']
usr_addr = ['192.168.0.1','192.168.0.1','192.168.0.1','192.168.0.1']
usr_num = 4
# -----------------------------------------------------------------------------
# 3. input processing
# -----------------------------------------------------------------------------
print('3. input processing','\n\n');
ostr = "Server listen to IP=localhost, port=12345 as default. \n \
type y to use default settings, type n to specify \n"
print(ostr);
istr = sys.stdin.readline().strip()
if ( istr == 'y' ):
host = 'localhost' #sys.argv[1]
port = 12345 #sys.argv[2]
elif ( istr == 'n' ):
ostr = "Pls specify the IP to listen to"
print(ostr);
host = sys.stdin.readline().strip()
ostr = "Pls specify the port to listen to"
print(ostr);
port = sys.stdin.readline().strip()
else:
ostr = "setting error!"
print(ostr);
sys.exit()
print('--------------------------\n')
ostr = "setting is:"
print(ostr)
print(host,port,'\n')
print('--------------------------\n')
verbose = 1
test_mode = 0
# -----------------------------------------------------------------------------
# 4. function
# -----------------------------------------------------------------------------
print('4. function','\n');
# -----------------------------------------------
# 4.1 utility
# -----------------------------------------------
def printv(msg):
if (verbose ==1):
print(msg);
def print_usr_info_stat():
print('\nprint_usr_info_stat:');
for i in range(0,usr_num):
print(i,usr_name[i],usr_passwd[i],usr_stat[i],usr_addr[i]);
print('\n');
# -----------------------------------------------
# 4.2 usr info stat proc
# -----------------------------------------------
# login
def login(name,passwd,addr):
valid = 0;
for i in range(0,usr_num):
if (usr_name[i] == name and usr_passwd[i] == passwd):
usr_stat[i] = 'login';
usr_addr[i] = addr;
if (1 == test_mode):
print(name,passwd,addr,': login\n');
else:
s.sendto(b'login succeed', addr)
print('reply: ',name,'login succeed');
valid = 1;
if (0 == valid):
if (1 == test_mode):
print('usr name not found/wrong passwd\n');
else:
s.sendto(b'login fail', addr)
print('reply: ',name,'usr name not found/wrong passwd\n');
# logout
def logout(name,passwd,addr):
valid = 0;
for i in range(0,usr_num):
if (usr_name[i] == name):
usr_stat[i] = 'logout';
usr_addr[i] = 'xxx';
if (1 == test_mode):
print(name,': logout\n');
else:
s.sendto(b'logout succeed', addr);
print('reply: ',name,'logout succeed');
valid = 1;
if (0 == valid):
if (1 == test_mode):
print('usr name not found/wrong passwd\n');
else:
s.sendto(b'logout fail', addr)
print('reply: ',name,'logout fail');
def chk_login(from_name,to_name,addr):
valid = 0;
for i in range(0,usr_num):
if (usr_name[i] == from_name):
for j in range(0,usr_num):
if (usr_name[j] == to_name):
if ( usr_stat[i]=='login' and usr_stat[j] == 'login'):
valid = 1;
if (1 == test_mode):
print('chk_login pass');
return(1);
if(valid == 0):
if (1 == test_mode):
print('check login fail\n');
else:
s.sendto(b'check login fail', addr)
print('reply: ',from_name,to_name,'check login fail\n');
return(0);
# -----------------------------------------------
# 4.3 main proc
# -----------------------------------------------
# msg_dispatch
def msg_proc(from_name,to_name,to_msg,addr):
if (1 == chk_login(from_name,to_name,addr)):
if (1 == test_mode):
print('server got it\n');
else:
#s.sendto(b'server got it\n',addr)
#print('reply: ','server got it\n');
print ("Enter: ")
data = sys.stdin.readline().strip()
#s.sendall(data.encode())
s.sendto(data.encode(),addr)
print('reply: \n',data);
# decode and dispatch
def decode_dispatch(message,addr):
# print user information
#if (1 == test_mode):
# print_usr_info_stat();
# input
if (1 == test_mode):
msg = message.split('#');
print('splited msg:',msg,addr);
else:
a = message.decode();
msg = a.split('#');
print('received from:',addr,'\n messgae:',message);
# message processing
if(msg[1] == 'login'):
login(msg[2],msg[3],addr);
elif(msg[1] == 'logout'):
logout(msg[2],msg[3],addr);
elif(msg[1] == 'msg'):
msg_proc(msg[2],msg[3],msg[4],addr);
print('\n');
# -----------------------------------------------------------------------------
# 5. main
# -----------------------------------------------------------------------------
''' '''
# ----------------------------------------------------
# 5.1 connect
# ----------------------------------------------------
print('5.1 connect','\n');
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
# ----------------------------------------------------
# 5.2 main loop
# ----------------------------------------------------
print('5.2 main loop','\n');
while 1:
try:
message,address = s.recvfrom(8192)
decode_dispatch(message,address)
except (KeyboardInterrupt, SystemExit):
raise
except:
traceback.print_exc()
# -----------------------------------------------------------------------------
# 6. incermental/regression test (FIXME: auto)
# Usage: comment out main then you can make test
# -----------------------------------------------------------------------------
'''
print('6. incermental/regression test\n');
# ------------------------------------------------
# 6.1 verbose test
# ------------------------------------------------
print('verbose test start');
print('------------------------------------------\n');
verbose = 1
printv('verbose test,if you see this msg,test pass');
# printv('verbose test,if you see this msg,test pass',verbose);
verbose = 0;
printv('verbose test,if you see this msg,test fail');
print('verbose test end');
print('------------------------------------------\n');
'''
# ------------------------------------------------
# 6.2 usr info test
# ------------------------------------------------
'''
print('usr info test start\n');
print('------------------------------------------\n');
# login case
login('Ben','B123' ,'192.168.0.6');
login('Tom','T123' ,'192.168.0.7');
login('John','J123','192.168.0.8');
print_usr_info_stat()
# logout case
logout('Ben', 'B123','192.168.0.6');
logout('Tom', 'T123','192.168.0.7');
logout('John','J123','192.168.0.8');
print_usr_info_stat();
chk_login('Ben','John','192.168.0.8');
login('Ben','B123' ,'192.168.0.6');
login('Tom','T123' ,'192.168.0.7');
login('John','J123','192.168.0.8');
chk_login('Ben','John','192.168.0.8');
print('\nusr info test end');
print('------------------------------------------\n');
'''
# ------------------------------------------------
# 6.3 test decode_dispatch
# NOTEME: decode needed to be comment out
# ------------------------------------------------
'''
print('test decode_dispatch start\n');
print('------------------------------------------\n');
#
print('Round1:\n');
message1 = '#login#John#J123#'
message2 = '#logout#John#J123#'
message3 = '#msg#John#Tom#Hi,how are doing?'
message4 = '#msg#Tom#John#Very good!'
decode_dispatch(message1,'192.168.0.6');
decode_dispatch(message2,'192.168.0.7');
decode_dispatch(message3,'192.168.0.8');
decode_dispatch(message4,'192.168.0.9');
#
print('Round2:\n');
message2 = '#login#Tom#T123#'
decode_dispatch(message1,'192.168.0.6');
decode_dispatch(message2,'192.168.0.7');
decode_dispatch(message3,'192.168.0.8');
decode_dispatch(message4,'192.168.0.9');
print('test decode_dispatch end\n');
print('------------------------------------------\n');
'''
# ------------------------------------------------
# 6.4 function test
# Usage: turn main loop,set test_mode = 0
# use cmd from decode_dispatch at client end
# ------------------------------------------------
# -----------------------------------------------------------------------------
# 7. end
# -----------------------------------------------------------------------------
print('\nchip_udp_server.py end','\n');
Pyhont Client端程序:
#!/usr/bin/env python
# =============================================================================
# Copy Rights @Chip, All Rights Reserved
#
# File: chip_udp_client.py
# Description:
# udp client program
# #[cmd type]#[param1]#[param2]#
# login - user name - passwd
# logout - user name - passwd
# msg - from - to
# Please refer to chip_udp_server.py Line 36-41 for detailed infomation
# HOWTORUN:
#
# V0.1: Initial Version
# Chip,2016/6/10
# V1.0: add ip/port setting
# Chip,2015/6/21
#
# =============================================================================
# -----------------------------------------------------------------------------
# 1. start/import
# -----------------------------------------------------------------------------
print('1. start/import','\n');
import sys,socket,time
# -----------------------------------------------------------------------------
# 2. data structure
# -----------------------------------------------------------------------------
print('2. data structure','\n');
# -----------------------------------------------------------------------------
# 3. input processing
# -----------------------------------------------------------------------------
print('3. input processing','\n');
ostr = "Clent listen to IP=localhost, port=12345 as default. \n \
type y to use default settings, type n to specify \n"
print(ostr);
istr = sys.stdin.readline().strip()
if ( istr == 'y' ):
host = 'localhost' #sys.argv[1]
textport = '12345' #sys.argv[2]
elif ( istr == 'n' ):
ostr = "Pls specify the IP to connect to"
print(ostr);
host = sys.stdin.readline().strip()
ostr = "Pls specify the port to connect to"
print(ostr);
textport = sys.stdin.readline().strip()
else:
ostr = "setting error!"
print(ostr);
sys.exit()
print('--------------------------\n')
ostr = "setting is:"
print(ostr)
print(host,textport,'\n')
print('--------------------------\n')
# host = 'localhost' #sys.argv[1]
# textport = '51423' #sys.argv[2]
# -----------------------------------------------------------------------------
# 4. function
# -----------------------------------------------------------------------------
print('4. function','\n');
# -----------------------------------------------------------------------------
# 5. main
# -----------------------------------------------------------------------------
''' '''
print('5. main','\n');
# ----------------------------------------------------
# 5.1 connect
# ----------------------------------------------------
print('5.1 connect','\n');
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ----------------------------------------------------
# 5.2 main loop
# ----------------------------------------------------
print('5.2 main loop','\n');
ref = "\n \
Reference msg example: \n \
#login#John#J123# \n \
#login#Tom#T123# \n \
\n \
#msg#John#Tom#Hi,how are doing? \n \
just put msg behind \"#msg#[]#[]#[]\" \n \
\n \
if you want to quit, example as #logout#John#J123# \n \
"
print(ref);
try:
port = int(textport)
except ValueError:
# That didn't work. Look it up instread.
port = socket.getservbyname(textport, 'udp')
while 1:
# connect
s.connect((host, port))
# input
print ("Enter: ")
data = sys.stdin.readline().strip()
# send
s.sendall(data.encode())
s.shutdown(1)
print ("Looking for replies; press Ctrl-C or Ctrl-Break to stop.")
# receive
buf = s.recv(2048)
if not len(buf):
break
print ("Received:\n %s\n" % buf)
# -----------------------------------------------------------------------------
# 6. incermental/regression test (FIXME: auto)
# Usage: comment out main then you can make test
# -----------------------------------------------------------------------------
print('6. incermental/regression test\n');
# -----------------------------------------------------------------------------
# 7. end
# -----------------------------------------------------------------------------
print('\nchip_udp_server.py end','\n');
Android/Java程序:
package org.crazyit.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.widget.EditText;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SimpleClient extends Activity
{
EditText show;
@Override
public void onCreate(Bundle savedInstanceState)
{
try{
// 创建一个DatagramSocket对象
DatagramSocket socket = new DatagramSocket(51423);
//创建一个InetAddree
InetAddress serverAddress = InetAddress.getByName("192.168.1.105");
String str = "#login#John#J123#"; // 要传输的数据
byte data [] = str.getBytes();
//创建一个DatagramPacket对象,并指定要地址以及端口号
DatagramPacket packet = new DatagramPacket(data,data.length,serverAddress,51423);
//调用socket对象的send方法,发送数据
socket.send(packet);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.crazyit.net"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".SimpleClient"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- 授权访问互联网-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
4. 运行及测试
本程序使用ActivePython 3.3平台。
运行程序,交互过程如下图所示:
Server Log
Client Log
第二张图片不能上传???
Android平台使用QPython
第三张图片不能上传???
Android使用Java
5. 后记
已经实现的详情参见运行及测试;
后续提升项参见chip_udp_server.py文件头
经验之谈,但一家之言;持续更新,欢迎探讨。