4. 实现QNX与Android的Socket通信
任务说明
在QNX侧创建TCP Server,Android侧创建TCP Client,通过局域网建立连接并实现双向字符串消息传递。QNX侧监听指定端口,Android侧主动连接后,双方均可发送消息,对端实时接收并打印。
环境与依赖
- QNX侧:QNX SDP 7.0+,支持标准POSIX Socket API,无需额外库
- Android侧:Android Studio,minSdk 21+,需在Manifest声明
INTERNET权限 - 网络:QNX设备与Android设备处于同一局域网,QNX侧IP需预先获知(示例用
192.168.1.100)
QNX侧实现(TCP Server)
// qnx_tcp_server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFSIZE 256
int main() {
int server_fd, client_fd;
struct sockaddr_in addr;
char buf[BUFSIZE];
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) { perror("socket"); return 1; }
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind"); return 1;
}
if (listen(server_fd, 1) < 0) { perror("listen"); return 1; }
printf("QNX Server listening on port %d...\n", PORT);
client_fd = accept(server_fd, NULL, NULL);
if (client_fd < 0) { perror("accept"); return 1; }
printf("Android client connected.\n");
// 双向通信循环:先收后发
while (1) {
memset(buf, 0, BUFSIZE);
int n = recv(client_fd, buf, BUFSIZE - 1, 0);
if (n <= 0) { printf("Connection closed.\n"); break; }
printf("Received from Android: %s\n", buf);
printf("QNX reply: ");
fgets(buf, BUFSIZE, stdin);
buf[strcspn(buf, "\n")] = 0;
if (send(client_fd, buf, strlen(buf), 0) < 0) { perror("send"); break; }
}
close(client_fd);
close(server_fd);
return 0;
}
编译:qcc -o qnx_server qnx_tcp_server.c,运行:./qnx_server。代码先阻塞等待Android连接,连接建立后进入收发循环。
Android侧实现(TCP Client)
// MainActivity.java 关键部分
public class MainActivity extends AppCompatActivity {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
private TextView tvStatus, tvReceived;
private EditText etMessage;
private static final String SERVER_IP = "192.168.1.100";
private static final int SERVER_PORT = 8888;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvStatus = findViewById(R.id.tvStatus);
tvReceived = findViewById(R.id.tvReceived);
etMessage = findViewById(R.id.etMessage);
new Thread(this::connectServer).start();
findViewById(R.id.btnSend).setOnClickListener(v -> {
String msg = etMessage.getText().toString();
if (!msg.isEmpty() && out != null) {
new Thread(() -> out.println(msg)).start();
etMessage.setText("");
}
});
}
private void connectServer() {
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(() -> tvStatus.setText("Connected to QNX"));
String line;
while ((line = in.readLine()) != null) {
String finalLine = line;
runOnUiThread(() -> tvReceived.append("QNX: " + finalLine + "\n"));
}
} catch (IOException e) {
runOnUiThread(() -> tvStatus.setText("Error: " + e.getMessage()));
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try { if (socket != null) socket.close(); } catch (IOException ignored) {}
}
}
布局文件需包含tvStatus、tvReceived、etMessage、btnSend四个控件。Manifest中添加<uses-permission android:name="android.permission.INTERNET"/>。
验证方法
- 在QNX终端运行
./qnx_server,看到监听日志 - 启动Android App,观察状态栏显示“Connected to QNX”
- 在Android输入框发送“Hello QNX”,QNX终端应打印
Received from Android: Hello QNX - 在QNX终端输入“Hello Android”并回车,Android的
tvReceived区域应显示QNX: Hello Android - 双向各发送一条消息且对端正确显示,即判定通信成功
常见问题
- 连接失败:确认QNX IP正确、防火墙未拦截8888端口、两端在同一网段
- Android收不到消息:QNX侧
send后需加\n换行符(示例中fgets已去除换行,需手动拼接),否则Android的readLine()会阻塞 - QNX侧
recv返回0:Android端Socket被关闭,属正常断开