哈哈哈哈哈!这是笔者第一次写这种东西,项目是我们大二的一个大创组的项目:
1>硬件端:stm32f429,红外线感应,esp8266模块,ov5640摄像头,步进电机,等等。
主要是采集移动物体的图像jpg,通过无线传输模块传递给服务器。这里将硬件当作tcp客户端。
2>服务器端:java写的,Java建立tcp服务器代码如下:
public static void main(String[] args) throws IOException{
ServerSocket ss=new ServerSocket(5670);//tcp服务器
socketserve socketServer = new socketserve(2017);//websocket服务器
socketServer.start();
while(true) {
Socket s=ss.accept();
socketT t=new socketT(s,i,socketServer );
new Thread(t).start();
i++;
}
}
}
/// 硬件的tcp服务器
class socketT implements Runnable{
private Socket client;
private int i;//照片个数
private socketserve android;
InputStream in=null;
public socketT(Socket client,int i,socketserve android ) {
this.client=client;
this.i=i;
this.android=android;
}
@Override
public void run() {
int j,c=0;
int d=0;
try {
in=client.getInputStream();
byte []data =new byte[300000];
byte []data1 = null;
for(j=0;d!=0xFF||c!=0xD9;) {
d=c;
c=in.read();
if(c!=-1) {
data[j]=(byte)c;
j++;
}
}
data[j]=-2;
data1=new byte[j+1];
for(;j>=0;j--)
data1[j]=data[j];
//发送给app
android.sendToclient(data1);//websocket 服务器主动推送给手机
//存入电脑
FileOutputStream op=new FileOutputStream(new File("D:/p/"+Integer.toString(i)+".jpg"));
op.write(data1);
op.close();
///人脸识别调用
/* new Thread(new Runnable() {
byte[] data2=null;
@Override
public void run() {
picture.FeatureOrbLannbased("D:/p/"+Integer.toString(i)+".jpg","D:/p3/"+Integer.toString(i)+".jpg");
FileInputStream oo;
try {
oo = new FileInputStream(new File("D:/p3/"+Integer.toString(i)+".jpg"));
data2=new byte[oo.available()];
oo.read(data2);
android.sendToclient(data2);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();*/
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里,我们不知道一张照片的大小是多大,所以只能用其结束符进行捕捉:jpg图片的文件是十六进制数,每张jpg图片以0xFF 0xD8开始,以0xFF 0xD9结束;所以我们从client 得到的inputsteam中读取字节,读到结束符的时候就代表一张图片的数据已经全部接收,就可以转化为想要的图片了。 值得我们注意的是:有时候inputsteam中的字节已经全部读取完毕,但是还没读到结束符;原因是一般是这样的:客户端(无论是硬件,还是在电脑上模拟的)发送大文件时候是一段一段发送的,比如我的硬件是每次发送1024个字节,那一张高质量图片要将近1M,所以不能一次发送,于是就必须等待指导有结束符才结束。
还有:这里是tcp短链接,要想长连接只需将其中的读取字节部分写入死循环即可,就是处理完一张照片,将byte[] data数组重新初始化,继续从in中读取。in和client一旦关闭,tcp断开。当然长连接已不是一直的,据说是2个小时会断开,我们用的局域网,额额额,晚上建立链接,早上起来还没断。
3>服务器端的websocket长连接;这是好东西,可以实现服务器端的信息向客户端的推送,实现起来也很简单。狠狠的踢开http(hahahahaha!);httpok也有封装这类东西。
public class socketserve extends WebSocketServer{
public socketserve(int port)throws UnknownHostException{
super(new InetSocketAddress(port));
}
public socketserve(InetSocketAddress address) {
super(address);
}
@Override
public void onClose(WebSocket webSocket, int i, String s, boolean b) {
System.out.println("duankai");
}
@Override
public void onError(WebSocket webSocket, Exception e) {
if (null != webSocket) {
webSocket.close(0);
}
e.printStackTrace();
}
@Override
public void onMessage(WebSocket webSocket, String s) {
}
@Override
public void onOpen(WebSocket webSocket, ClientHandshake clienthandshake) {
sendToclient("OPEN");
System.out.println("有客户已经链接上服务器");
}
@Override
public void onStart() {
// TODO Auto-generated method stub
}
//
public void sendToclient (String message) {
Collection<WebSocket> connections = connections();
//将消息发送给每一个客户端
for (WebSocket client : connections) {//这里需要判断客户端是否是硬件的主人,如果是就发送信息
client.send(message);
}
}
public void sendToclient(ByteBuffer b) {
Collection<WebSocket> connections = connections();
//将消息发送给每一个客户端
for (WebSocket client : connections) {
client.send(b);
}
}
public void sendToclient(byte[] message) {
Collection<WebSocket> connections = connections();
//将消息发送给每一个客户端
for (WebSocket client : connections) {
client.send(message);
}
}
}
很简单,可能是我们使用的太低级,嗯!可以发送String byte[] bytebuffer三种;主动推送给客户端。
4>android客户端;我主要说我们的通信链接模块
我们将其写道一个后台运行中,当出发app的某个开关之后,后台一直运行,直到将他杀死。
public class service extends Service {
private websocket client;
private static final String url = "ws://你的服务器ip:你的服务器端口/";
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
}
@Override
public void onDestroy() {
client.close();
}
@Override
public void onStart(Intent intent, int startid) {
websocket_init();
}
/
private void websocket_init(){
client = new websocket(URI.create(url)) {
@Override
public void onMessage(ByteBuffer message) {
byte[] dat=new byte[message.remaining()];
message.get(dat, 0, dat.length);//得到服务器端推送信息
FileOutputStream fout;
try {
fout = new FileOutputStream(new File(Environment.getExternalStorageDirectory()+"/dachuang/",Integer.toString(data.shu()+1)+".jpg"));//存入手机固定的内存文件夹
fout.write(dat);
fout.close();
} catch (Exception e) {
e.printStackTrace();
}
addnotification("接收到警报消息,点击查看");//添加消息栏提醒
}
@Override
public void onMessage(String message) {
if(message=="OPEN");//接收到服务器的消息,这个消息是 ,自己看吧,对照服务器端代码
addnotification("链接成功");
}
};
client.connect();
}
/ ///
private void addnotification(String str) {
NotificationManager manager=(NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification=new Notification();
//设置显示在手机最上边的状态栏的图标
notification.icon=R.drawable.family;
notification.tickerText="注意了,我被扔到状态栏了";
notification.defaults=Notification.DEFAULT_SOUND;
notification.defaults =Notification.DEFAULT_VIBRATE;
notification.audioStreamType=android.media.AudioManager.ADJUST_LOWER;
Intent intent=new Intent(this,option_3.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_ONE_SHOT);
//点击状态栏的图标出现的提示信息设置
notification.setLatestEventInfo(this,"警报信息:",str,pendingIntent);
manager.notify(1,notification);
}
}
N>是的,也许你会问,你需要jar,那就去下载吧!https://download.csdn.net/download/lixinkailixinkai/10623020
还有人脸识别:下回再说。