Samer Bastawy Samer Bastawy - 6 months ago 78
Android Question

Why my android client cannot recieve string message from winsock c++ server?

I am trying to build an android app that communicates with a c++ server running on windows using TCP sockets. I successfully sent a string from the app to the server but I cannot do the other way around. Please help me because I have been trying with this issue for a while now.

Android Client:

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();
}
}


The 'count' always returns 0 despite the fact that on the windows c++ server side it says that it has successfully sent the 25 bytes.

C++ Winsock Server:

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;
}


Server console output:


Start Receving

AndroidID - Hello World...

Done Bytes Sent: 25

0

Press any key to continue . . .

Answer

The problem is that you are calling oos.close() after sending the initial string to the server.

DataOutputStream extends FilterOutputStream, and the behavior of its close() method is documented:

FilterOutputStream.close()

The close method of FilterOutputStream calls its flush method, and then calls the close method of its underlying output stream.

In this case, the "underlying output stream" is the socket's outputStream, and its close() behavior is also documented:

Socket.getOutputStream()

Closing the returned OutputStream will close the associated socket.

Socket.close()

Closes this socket.

Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.

Once a socket has been closed, it is not available for further networking use (i.e. can't be reconnected or rebound). A new socket needs to be created.

Closing this socket will also close the socket's InputStream and OutputStream.

If this socket has an associated channel then the channel is closed as well.

So, your client is closing the socket connection before it can read the server's reply string. You need to remove that call to oos.close() so yo keep the connection open until you are done reading.

On the server side, simply due to timing, your code may be able to call send() and put the reply string into the socket's outbound buffer before the socket detects the disconnect. The buffer is not actually transmitted by send() itself, it is queued to the OS kernel, which will transmit the data in the background. So send() will return success instead of failure if the reply string is buffered before the disconnect is detected.