上学期搞定了小车,现在终于结束了大机器人,趁还没真正进入考研复习的高潮赶紧把以前的代码整理整理。
先讲讲我们那小车,2台手机+车体组成。一个手机放车上作为server,用其摄像头、陀螺仪、磁力计来获取图像、确定小车方向。另一台手机负责控制,作为client,并画出小车行进图。如何从server获取陀螺仪、磁力计角度,又如何把client的控制命令发送给server就成了一个问题。这里我们使用socket双向通信。
先讲
client
部分
// Socket Client connect to Server
connectButton.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
try
{
ip = mEditText02.getText().toString();
Thread thread = new Thread(new mSocketConnectRunnable2());
thread.start();
// thread.sleep(100);
goToControl(); //进行控制命令的处理
connectButton.setVisibility(View.INVISIBLE);
mEditText02.setVisibility(View.INVISIBLE);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
两台手机都连接到同个wifi,这个就不多讲了。首先你得有个EditText填写server的IP地址,然后有个按钮,点击启动个线程,负责与server通信,这里传给Thread的构造函数调用Runnable接口。socket其实就是对某一个服务器的一个端口进行连接,连接上后就形成会话。由于这里socket是全双向的字节流,所以连上的时候其本身就已经具备了双向通信能力。
然后我们看它调用的接口,怎么连接和接受server发来的数据……
//Socket Client
public class mSocketConnectRunnable2 implements Runnable
{
@Override
public void run()
{
try
{
mSocket02 = new Socket(ip, intSocketServerPort);
if(mSocket02.isConnected())
{
Log.i(TAG, "Socket Client is connected to Server.");
strTemp01="Socket Client is connected to Server.";
}
BufferedReader br = new BufferedReader(new InputStreamReader(mSocket02.getInputStream()));
while (true)
{
strTemp01 = br.readLine();
if(!strTemp01.isEmpty())
handler.post(rReceiveInfo);
}
}
catch(Exception e)
{
if(bIfDebug)
{
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
}
}
ip上面说了,intSocketServerPort是socket端口,我这里设置为8080。mSocket02就像个水管,可以往里灌水也可以抽水。这里通过BufferedReader获得字节流,用handler传递进行数据处理。这里推荐用handler,不仅增加代码可度性,更容易避免莫名其妙的bug……
以上是建立socket连接并且从server获取字节流的过程,下面是发送字节流的部分……
public static void action(String a){
//当Socket连接正常且不为空时,流输出给server
if(mSocket02!=null && mSocket02.isConnected() && !a.equals(""))
{
try
{
bw = new BufferedWriter(new OutputStreamWriter(mSocket02.getOutputStream()));
bw.write(a+"\n");
bw.flush();
}
catch (Exception e)
{
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
}
这里,比如我用 action(“forward”),则字节流将forward发往server,至于这里流输出,不过多解释,详细的需要自己仔细查看socket。
然后是
server
部分……这里我们设置一个按钮用于开启socket server
// Run Socket Server
mButton01.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
mButton01.setEnabled(false);
mButton02.setEnabled(true);
setContentView(R.layout.i3);
Thread thread = new Thread(new mSocketConnectRunnable1());
thread.start();
}
});
这里也是用Thread的构造函数调用Runnable接口
//Socket Server
public class mSocketConnectRunnable1 implements Runnable
{
@Override
public void run()
{
// TODO Auto-generated method stub
try
{
mServerSocket01 = new ServerSocket(intSocketServerPort);
mServerSocket01.setReuseAddress(true);
Log.i(TAG, strDebugPreFix+"Socket Server is Running: "+intSocketServerPort);
while (!mServerSocket01.isClosed())
{
mSocket01 = mServerSocket01.accept();
Thread read = new Thread(new Runnable()
{
BufferedReader br = new BufferedReader(new InputStreamReader(mSocket01.getInputStream()));
@Override
public void run()
{
try
{
while (mSocket01.isConnected())
{
msg = br.readLine();
Handler01.post(rManualControl);
}
}
catch (Exception e)
{
if(bIfDebug)
{
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
}
});
read.start();
//在接受数据的同时发送数据,实现双向通信
Thread write = new Thread (new Runnable()
{
@Override
public void run()
{
while (mSocket01.isConnected())
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Handler01.post(rSendStr);
}
}
});
write.start();
}
}
catch(Exception e)
{
if(bIfDebug)
{
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
}
}
public Runnable rSendStr = new Runnable(){
public void run()
{
try
{
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(mSocket01.getOutputStream()) );
strMove = strMoveFlag
+ " " + String.valueOf((int) gyrAngle)
+ " " + String.valueOf( ( ((int)corrected_a) +((accX>3)?90:180) )%360) //由于小车姿态问题,需要进行修正
+ " " + strQR
+" \n";
bw.write(strMove);
bw.flush();
strQR = "0"; // accX>3
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
这里用了read write两个thread,分别负责流输入和流输出。这里唯独要提的就是write部分,加上sleep控制流输出频率,不然会造成堵塞。将BufferedWriter通过handler放到Runnable中解决莫名其妙的问题(我的基础不行……惭愧惭愧……)。
PS:用handler解决部分问题,多亏了队友
sununs11.这里是我们组项目中截下的代码,会有很多无关于本文双向通信的代码,请无视……后续会放出全部代码与代码解释……这代码是干什么的???请看这个简短视频:
基于OpenCV和Android的语音物标识别车
by:season