【发布时间】:2023-03-15 13:11:01
【问题描述】:
我正在尝试构建一个 android 应用程序,该应用程序使用 TCP 套接字与在 Windows 上运行的 c++ 服务器进行通信。我成功地从应用程序向服务器发送了一个字符串,但我无法反其道而行之。请帮助我,因为我一直在尝试解决这个问题。
Android 客户端:
String mystr="Hello World...";
char[] buffin=new char[128];
String input =null;
Integer count = 0;
class TextRcv extends AsyncTask<Void, Void, Integer>
{
@Override
protected Integer doInBackground(Void... params) {
//Sending a string (WORKING)
Socket clientSocket = null;
try {
clientSocket= new Socket("192.168.1.5",8889);
DataOutputStream oos= new DataOutputStream(clientSocket.getOutputStream());
oos.writeBytes(mystr);
//oos.writeBytes(String.valueOf(mystr.length()));//write the length of the string first
//byte[] bufferout=mystr.getBytes();
//oos.write(bufferout, 0, bufferout.length);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
//Recieving a String (Not working)
try {
BufferedReader in = null;
if (clientSocket != null)
{
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
else
{
Log.e("samer ","CLIENTSOCKET NULL");
}
if (in != null)
{
count=in.read(buffin);
}
else
{
Log.e("samer ","BUFFERREADER NULL");
}
if(count>0)
{
input=new String(buffin,0,count);
}
if (clientSocket != null) {
clientSocket.close();
}
} catch (IOException e) {
Log.i("samer count: ",String.valueOf(count));//RETURNS 0 !!
Log.i("buff samer: ", String.valueOf(buffin));//Returns garbage
e.printStackTrace();
}
return count;
}
@Override
protected void onPostExecute(Integer count) {
super.onPostExecute(count);
Toast toast=Toast.makeText(getApplicationContext(),String.valueOf(count),Toast.LENGTH_LONG);
toast.show();
}
}
尽管在 windows c++ 服务器端它说它已成功发送 25 个字节,但“计数”始终返回 0。
C++ Winsock 服务器:
int main(int argc, const char *argv[])
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int valread;
int iSendResult;
char * recvbuf;
char *recvstr;
int recvbuflen = DEFAULT_BUFLEN;
recvbuf = (char*)malloc((recvbuflen + 1) * sizeof(char));
recvstr = (char*)malloc((recvbuflen + 1) * sizeof(char));
char* AndroidID;
char *sendbuf = "Client: sending data test";
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
if (ClientSocket != INVALID_SOCKET)
{
cout << "Start Receving" << endl;
//------Start Receiving
//-----------------------------------
int lengthofrecv=recv(ClientSocket, recvbuf, recvbuflen, 0);
recvbuf[lengthofrecv] = '\0';//append \0 to use with printf()
AndroidID = recvbuf;
printf("AndroidID - %s \n", recvbuf);
cout << " \n Done ";
//---Start Sending to android
//-----------------------------------------
iResult = send(ClientSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR)
{
wprintf(L"send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %d\n", iResult);
cout << WSAGetLastError() << endl;
}
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
服务器控制台输出:
开始接收
AndroidID - Hello World...
发送的完成字节数:25
0
按任意键继续。 . .
【问题讨论】:
-
如果 Java 读取代码在发送代码发送之前运行会发生什么情况,它是读取 0 字节还是阻塞?
-
@RichardCritten:
read(char[])文档说:“此方法将阻塞,直到某些输入可用,发生 I/O 错误,或到达流的末尾。” -
所以你建议我的代码中的读取操作实际上是在服务器发送之前运行的。正确的?如果是这样,你认为我应该怎么做?我是否关闭套接字并为每个读取或写入操作重新打开它?或者我应该在读取操作之前延迟,以便给服务器一些时间将数据放到网络上?处理它的最佳方法是什么? (如果我理解正确)
-
"我是否关闭套接字并在每次读取或写入操作时重新打开它" - 当然不是!真正的问题是您的代码在有机会读取之前关闭了套接字。你需要解决这个问题。