我正在尝试创建一个为每个特定按钮发送一个字节的控制器。
为了进行测试,我在Python中创建了一个客户端以及C中的服务器。结果如预期的那样,如果我按下按钮它会发送0x1例如,直到我释放按钮,因为它然后发送另一个字节告诉服务器我发布了按钮(0x2)。服务器收到这个罚款。
现在我正在尝试用Java做同样的事情,更具体的是Android。当我按下Android应用程序中的按钮时,它发送0x1,服务器接收到该消息,但在释放按钮后,服务器仅在断开客户端后才接收0x2字节。
当然,我想要与在Python中使用我的客户端时相同的结果。
Python中的客户端:
class MainWindow(QWidget, Ui_Form):
def __init__(self, TCP_IP, TCP_PORT):
super(MainWindow, self).__init__()
""" TCP related """
self.TCP_IP = TCP_IP
self.TCP_PORT = TCP_PORT
self.sock = None
""" Ui related """
self.setupUi(self)
self.setWindowTitle("RC Car Controller")
self.setWindowIcon(QIcon("6269-200.png"))
""" Initialize the socket """
self.initialize_socket()
def initialize_socket(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
self.sock.connect((self.TCP_IP, self.TCP_PORT))
except Exception as e:
print(e)
@pyqtSlot(name="")
def on_btnFullForward_pressed(self):
self.send_data(b'\x01')
@pyqtSlot(name="")
def on_btnFullForward_released(self):
self.send_data(b'\x02')
def send_data(self, data):
try:
self.sock.send(data)
except Exception as e:
print(e)
我在C中的服务器示例:
unsigned char buffer[1];
struct sockaddr_in serverAddr, clientAddr;
int tcpSocket, slen, n, conn;
void ConnectionSocket(char* ip){
/*Create TCP socket*/
tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
if (tcpSocket < 0) {
perror("ERROR opening socket");
exit(1);
}
memset(&serverAddr, '0', sizeof(serverAddr));
memset(buffer, '0', sizeof(buffer));
/*Configure settings in address struct*/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr(ip);
if (bind(tcpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
perror("ERROR on binding");
}
if(listen(tcpSocket, 10) == -1){
printf("Failed to listen\n");
}
slen = sizeof(clientAddr);
conn = accept(tcpSocket,(struct sockaddr *)&clientAddr, &slen); // Blocking!
}
void loop(){
while(1){
if (conn < 0) {
perror("ERROR on accept");
exit(1);
}
n = read(conn, buffer, 1);
if (n == NULL){
printf("Client has disconnected!, Trying to reconnect..\n");
emergency_stop();
reconnect_on_failed();
}else{
printf("Received packet from %s:%d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
control_car(buffer);
handle_pins();
}
}
}
void reconnect_on_failed(){
slen = sizeof(clientAddr);
conn = accept(tcpSocket,(struct sockaddr *)&clientAddr, &slen); // Blocking!
printf("Client has reconnected!\n");
}
Java(Android)客户端:
package com.example.gianni.rccar;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
ImageButton FullFoward;
ImageButton Forward;
ImageButton Backward;
ImageButton Left;
ImageButton Right;
EditText Ip;
Button Set;
WebView Cam;
public int port = 7891;
public Socket socket;
final byte[][] data = new byte[1][1];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FullFoward = (ImageButton) findViewById(R.id.buttonFullFoward);
Forward = (ImageButton) findViewById(R.id.buttonForward);
Backward = (ImageButton) findViewById(R.id.buttonBackward);
Left = (ImageButton) findViewById(R.id.buttonLeft);
Right = (ImageButton) findViewById(R.id.buttonRight);
Ip = (EditText) findViewById(R.id.editTextIp);
Set = (Button) findViewById(R.id.buttonSet);
Cam = (WebView) findViewById(R.id.Camera);
FullFoward.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
data[0] = new byte[]{0x1};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
data[0] = new byte[]{0x2};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
}
return false;
}
});
Forward.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
data[0] = new byte[]{0x3};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
data[0] = new byte[]{0x4};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
}
return false;
}
});
Backward.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
data[0] = new byte[]{0x5};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
data[0] = new byte[]{0x6};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
}
return false;
}
});
Right.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
data[0] = new byte[]{0x7};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
data[0] = new byte[]{0x8};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
}
return false;
}
});
Left.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
data[0] = new byte[]{0x9};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
data[0] = new byte[]{0x10};
new Thread(new myTask2(data[0])).start();
return true; // if you want to handle the touch event
}
return false;
}
});
Set.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new myTask(Ip.getText().toString())).start();
Cam.loadUrl("http://" + Ip.getText().toString() + ":9090/stream/video.mjpeg");
}
});
Cam.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
String message = "Camera Connection failed, is the server online? Please reload.";
Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
toast.show();
Cam.loadUrl("about:blank");
super.onReceivedError(view, request, error);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.reload) {
String message = "Reloading..";
Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT);
toast.show();
Cam.loadUrl("http://" + Ip.getText().toString() + ":9090/stream/video.mjpeg");
}
return super.onOptionsItemSelected(item);
}
private class myTask implements Runnable {
String address;
myTask(String address) {
this.address = address;
}
@Override
public void run() {
try {
socket = new Socket(this.address, port);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class myTask2 implements Runnable {
byte[] data;
myTask2(byte[] bytes) {
this.data = bytes;
}
@Override
public void run() {
try {
OutputStream out = socket.getOutputStream();
out.write(this.data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}