我目前正在尝试从Android智能手机向树莓派发送消息。 我通过此处给出的示例代码实现了Android-Client:
我将ip-address更改为端口,因此它可以与在pi上运行的服务器一起使用。该服务器是用c编写的,在切换到android之前,我实现了一个C客户端,到目前为止,它工作正常,没有任何问题。
服务器只需要接收一条消息,然后将其打印并停止,因此非常简单。
编辑3
我创建了用于调试和分析的新输出,现在我可能有一个不起作用的想法。据我所知,SendMessageTask
从未执行过。
服务器输出现在为:
成功-创建套接字
成功-绑定
听着
成功-接受
现在它停滞了,“ reading ...”从未打印过! (应该在while循环中发生)
在Android中,我收到以下必要输出:
D / TCP客户端:C:正在连接...
D / TcpOptimizer:TcpOptimizer-打开
->发生连接
当我按下“发送”按钮时:
D / myMessage1:按下按钮
D / myMessage:测试
但是我没有收到应记录在SendMessageTask
当我单击断开连接按钮时,服务器将打印:
客户端已断开连接
现在Android日志:
D /响应服务器:S:收到消息:'null'
D / sendMessageTask:尝试发送消息
D / TcpClient:无法发送-> mBufferOut为空
因此,我的猜测是,SendMessageTask
永远不会运行,直到由于断开连接而失败,但是为什么?
编辑3-结束
这是(已编辑的)服务器代码:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
int main(){
int welcomeSocket, newSocket, read_size;
char buffer[10000];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);
if (welcomeSocket == -1) {
printf("Could not create socket\n");
}else {
printf("Success - create socket\n");
}
/*---- Configure settings of the server address struct ----*/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = INADDR_ANY;
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
if(bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0){
printf("Error - Binding\n");
}else {
printf("Success - Binding\n");
}
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
if(newSocket < 0){
printf("Error - Accept\n");
}else {
printf("Success - Accept\n");
}
while( (read_size = recv(newSocket, buffer, 10000, 0)) > 0){
write(newSocket, buffer, strlen(buffer));
printf("reading...");
}
if(read_size == 0){
printf("Client disconnected");
fflush(stdout);
}
else if(read_size == -1){
printf("Error - recv failed");
}
return 0;
}
我不太确定其中的参数
welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);
仍然正确吗?
Android中的客户端代码为:
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static final String TAG = TcpClient.class.getSimpleName();
public static final String SERVER_IP = "192.168.4.1"; //server IP address
public static final int SERVER_PORT = 7891;
// message to send to the server
private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private PrintWriter mBufferOut;
// used to read messages from the server
private BufferedReader mBufferIn;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TcpClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* @param message text entered by client
*/
public void sendMessage(final String message) {
Runnable runnable = new Runnable() {
@Override
public void run() {
if (mBufferOut != null) {
Log.d(TAG, "Sending: " + message);
mBufferOut.println(message);
mBufferOut.flush();
}else{
Log.d(TAG, "Cannot send --> mBufferOut is null");
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
/**
* Close the connection and release the members
*/
public void stopClient() {
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.d("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
//sends the message to the server
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//receives the message which the server sends back
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in this while the client listens for the messages sent by the server
while (mRun) {
/*
mServerMessage = mBufferIn.readLine();
if (mServerMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(mServerMessage);
}
*/
}
Log.d("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
//class at on AsyncTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
我的(已编辑)Mainactivity(包括用于连接的AsyncTask)是
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;
public class MyActivity extends AppCompatActivity {
private TextView mTextMessage;
private TextView myAwesomeTextView;
private TcpClient mTcpClient;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(R.string.title_home);
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myActivity);
mTextMessage = (TextView) findViewById(R.id.message);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
myAwesomeTextView = (TextView)findViewById(R.id.editText);
//TCP connect
new ConnectTask().execute("");
//Buttons
final Button button_Send = findViewById(R.id.button_Send);
button_Send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Set text (debugging)
myAwesomeTextView.setText("My Awesome Text");
Log.d("myMessage1", "button pushed ");
//sends the message to the server
String message = "testing\0";
//String message = "testing\n\r";
if (mTcpClient != null) {
new SendMessageTask().execute(message);
//not needed just for debugging
Log.d("myMessage", "testing ");
}
}
});
final Button button_Disconnect = findViewById(R.id.button_Disconnect);
button_Disconnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mTcpClient != null) {
mTcpClient.stopClient();
}
}
});
}
@Override
protected void onPause() {
super.onPause();
if (mTcpClient != null) {
// disconnect
new DisconnectTask().execute();
}
}
/**
* Sends a message using a background task to avoid doing long/network operations on the UI thread
*/
public class SendMessageTask extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
// send the message
mTcpClient.sendMessage(params[0]);
Log.d("sendMessageTask", "try to send message ");
return null;
}
@Override
protected void onPostExecute(Void nothing) {
super.onPostExecute(nothing);
//nothing to do yet
}
}
/**
* Disconnects using a background task to avoid doing long/network operations on the UI thread
*/
public class DisconnectTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
// disconnect
mTcpClient.stopClient();
mTcpClient = null;
return null;
}
@Override
protected void onPostExecute(Void nothing) {
super.onPostExecute(nothing);
//nothing to do yet
}
}
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
@Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object and
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
@Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
Log.d("test", "response " + values[0]);
//process server response here....
}
}
}
EDIT#2 (失败行为仍然存在)
uncommented while(mRun)循环TcpClient的运行方法 ->认为可能在消息发送之前,套接字终于被关闭了。
将初始连接移到了onCreate()中,因此按钮将仅 处理发送并建立连接。
在发送消息后不再关闭套接字
答案 0 :(得分:1)
我设法做到了。
我换了线
new SendMessageTask().execute(message);
到
new SendMessageTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);
发送工作成功了。
我也将服务器代码更改为此:
#define MAX 2048
#define PORT 7891
#define SA struct sockaddr
// Function designed for chat between client and server.
void communicate(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n');
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed..\n");
exit(0);
}
else
printf("Server listening...\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..\n");
// Function for chatting between client and server
communicate(connfd);
// After chatting close the socket
if(close(sockfd) < 0){
printf("Error - closing socket...\n");
}
else{
printf("Socket successfully closed..\n");
}
}