i have an implementation to do in a college project, and i dont know how to avchive it!. my problem its like the title say, conect android with c++ via sockets.
c++ must manage at least a pair of sockets clients (android Devices) or more.
so i try ...
#include <iostream>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>
using namespace std;
int main()
{
int client, server;
int portnum = 1500;
bool isExit = false;
int bufsize = 1024;
char buffer[bufsize];
struct sockaddr_in server_addr;
socklen_t size;
//init socekt
client = socket(AF_INET, SOCK_STREAM, 0);
if(client < 0){
cout << "Error Estableciendo la conexion" << endl;
}
cout <<"server Socket conexion creada" << endl;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(portnum);
//biding soket
if(bind(client,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0){
cout << "Error Biding Socket" << endl;
exit(1);
}
size= sizeof(server_addr);
cout << "buscando clientes" << endl;
//escuchando sokets
listen(client,1);
//accept client
server = accept(client, (struct sockaddr*)&server_addr, &size);
if(server < 0){
cout<< "Error al Aceptar" << endl;
exit(1);
}
while(server >0){
strcpy(buffer,"server conectado---\n");
send(server,buffer,bufsize,0);
cout <<"conectado con el cliente" << endl;
cout << "Ingresad # paara terminar la conexion" << endl;
cout <<"client: ";
do{
recv(server,buffer,bufsize,0);
cout << "buffer" << " ";
if(*buffer == '#'){
*buffer = '*';
isExit=true;
}
}while(*buffer != '*');
do{
cout << "\n server: ";
do{
cin >> buffer;
send(server,buffer,bufsize,0);
if(*buffer == '#'){
send(server,buffer,bufsize,0);
*buffer = '*';
isExit=true;
}
}while(*buffer != '*');
cout << "Client: ";
do{
recv(server,buffer,bufsize,0);
cout << buffer << " ";
if(*buffer == '#'){
*buffer = '*';
isExit = true;
}
}while(*buffer != '*');
}while(isExit);
cout << "Conection Terminated..." << endl;
cout << "Goodbye..." << endl;
isExit =false;
exit(1);
}
close(client);
return 0;
}
to listen every conection (please if you see bad logic in my code let me know it and what i need to do to fix it)
and in android i make something like this in a class that its called from an activity only for testing...
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Socktest {
public void prueba() {
try {
Socket sock = new Socket("127.0.0.1",1234);
// Your Java Code Verbatim:
BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String test = br.readLine();
System.out.println(test);
sock.close();
} catch (Exception ex) {
System.out.println(ex.getCause().toString());
}
}
}
(please if you see bad logic let me knowit because i want to learn more from my failures)
and the server goes fine when i compiled, its standing by to recive a new conection but when a luch the android activity and i run the "conection class" it says access denied, i am working on linux mint if that afect...
i am going to be gratfull with you coments, suggestions and advices.
Socket sock = new Socket("127.0.0.1",1234); this line is your problem right here, 127.0.0.1 is the local loop IP, its actually an IP address that maps to the device the code is on, so your android client is never connecting to the machine where the c++ code is running, instead what you need to do is find the IP address of the machine your c++ code is running on then change 127.0.0.1 to that IP address.
If you're mobile is connected to a wifi router to which your c++ server is connected to, then this IP address will be the local IP address, and everything is simple
If you're mobile is connected to some mobile network, and your server is on a different network, then you need to find out the IP address of your machine exposed to the world (depending on Internet service providers configuration you might have an IP address that remains static, or an IP address that changes every time your connection to the ISP server resets)
You can find your machines exposed IP address by going to websites like http://whatismyipaddress.com/ , then if your machine is behind a router, you need to do port forwarding (in this case forward your port 1234 to your machines local IP address) you can take a look at this guide to understand how to do that.
So to avoid the complexity in the 2nd step I advise you to connect your mobile and your server in same local network (i.e your LAN) using a wifi router.
Ways to find the IP address of your machine:
In linux based machines just open a terminal and type ifconfig and look at eth0 your IP address will be right after inet addr:, for example like this inet addr:10.99.123.23
Related
I'm having a problem with communicating between a C++ TCP server example that I found online and a java android application that I just threw together to see how the two could communicate back and forth.
For the Android client I had originally tried the AsyncTask class, but I was running into the problem of the Android socket closing. That would then break the loop of my C++ server and cause the server program to end successfully. I instead used a thread that would keep the socket open for the purpose of sending as much data back and forth until the client is done.
In the Android client code below, if I get rid of all the code associated with the bufferedReader, then I can send as much string data to the server as I want as the socket stays alive. If I add it, like below, and attempt to use the readline() function, then the function fails and prints a fatal exception.
As for my question, for what reason would I not be able to use readline() to get data back from the C++ server? Is there anything glaringly obvious that I should do?
Android Java Client
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
e1 = findViewById(R.id.editText);
sockThread = new Thread(sockApp = new SocketApp(ip, port));
sockThread.start();
}
public void send_text(View v) {
message = e1.getText().toString();
try {
printWriter = new PrintWriter(sockApp.s.getOutputStream());
bufferedReader = new BufferedReader(new
InputStreamReader(sockApp.s.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
printWriter.write(message);
printWriter.flush();
String line;
try {
//bufferedReader.readline() and the stacktrace is printed
while((line = bufferedReader.readLine())!= null && line.length() > 0) {
System.out.println(line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
All this android app does is send string data to my computer with the C++ server on it and print it out. The SocketApp class just creates a socket with ip and port inputs.
C++ Server Receive/Send to Android Client
char buf[4096]
while (true) {
ZeroMemory(buf, 4096);
//wait for client to send data
//After java exception is thrown, recv prints its error statement below
int bytesReceived = recv(clientsocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR) {
cerr << "Error in recv " << endl;
break;
}
//cout << bytesReceived << endl;
if (bytesReceived == 0) {
cout << "client disconnected" << endl;
break;
}
cout << string(buf, 0, bytesReceived) << endl;
// echo message back to client
send(clientsocket, buf, bytesReceived + 1, 0);
}
The while block of C++ socket code to receive string data and then send it back
I created a C server and a java client. I was sending a command like ls through the client and server should execute it. However read in c server is still waiting for input. how to solve this problem.
Java client
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
class HelloWorld
{
public static void main(String... abc) {
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter ip and port : ");
String ip ;
String p;
String ss;
int port;
ip = br.readLine();
p = br.readLine();
port = Integer.parseInt(p);
Socket s = new Socket(ip,port);
OutputStream os = s.getOutputStream();
PrintWriter pw = new PrintWriter(os);
Scanner in = new Scanner(System.in);
ss = in.nextLine();
pw.print(s);
pw.flush();
pw.close();
}
catch(Exception e){
System.out.println("ERROR!!!");}
}
}
here is the c server.
#include"Headers.h"
void comm(char * s_port)
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[MAXBUFFER];
char newbuffer[MAXBUFFER];
char var[MAXBUFFER] = " > file.txt";
int n;
struct sockaddr_in serv_addr, cli_addr;
FILE *fp = NULL;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(s_port);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
if (newsockfd < 0)
error("ERROR on accept");
while (1)
{
bzero(buffer,1024);
n = read(newsockfd,buffer,1024);
if (strcmp(buffer , "exit\n") == 0)
break;
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
strcpy(newbuffer,"");
if (buffer[strlen(buffer) - 1] == '\n')
buffer[strlen(buffer) - 1] = '\0';
strcat(newbuffer, buffer);
strcat(newbuffer, var);
printf("%s",newbuffer);
system(newbuffer);
break;
if (n < 0) error("writing to socket");
}
close(newsockfd);
close(sockfd);
}
n = read(newsockfd,buffer,1024);
if (strcmp(buffer , "exit\n") == 0)
break;
You forgot to implement a protocol. You can't just read an arbitrary bunch of bytes from the connection and then treat it as a message. TCP has no conception of a message. If you want to send and receive messages, you have to define what you mean by a "message" and write code to send and receive that implements that definition.
There are probably other problems with your code, but this defect is so severe and so fundamental, you really need to fix it first.
If your definition of a message is "a sequence of ASCII characters not including a zero byte or a newline terminated by a newline", then you need to write code to receive such a sequence. You can't just call read and expect it to find the message boundaries since it has no idea that you use newline as a message boundary.
The main problem with your code is the way you handle strings in C.
Your server seems to assume that you are sending UTF-8 encoded strings over the network but strings in Java are encoded in UTF-16 by default. You will also need a way to ensure that each message buffer only contains valid Unicode characters. Each character in a Unicode string can use multiple bytes and you might get partial sent characters on the server side.
You have a small typo in the java program:
pw.print(s);
s is the socket, so you are sending s.toString().
I think you mean:
pw.print(ss);
Also, you need to decide on a message protocol, just as #DavidSchwartz points out.
Some useful links:
Protocol types
Understanding and designing socket message protocols
I am attempting to setup a TCP/IP socket connection between Java and C++, with Java on Windows and C++ on a Raspberry Pi. The message being transmitted is a Google Protocol Buffer message, with a proto set as below:
package package_name;
message Win2Pi{
optional int32 num1= 1;
optional int32 num2= 2;
optional int32 num3= 3;
optional int32 num4= 4;
optional bool logic1= 5;
optional bool logic2= 6;
optional bool logic3= 7;
optional bool logic4= 8;
optional bool logic5= 9;
optional int32 num5= 10;
optional bool logic6= 11;
}
I have the following code for Java (which acts as a client):
/* Java Code to Open Socket, Create Protobuf Message, and Send */
Socket clientSocket = new Socket(hostName, portNumber);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
WinToPi.Builder w2p = WinToPi.newBuilder();
w2p.setNum1(255);
w2p.setNum2(255);
w2p.setNum3(255);
w2p.setNum4(255);
w2p.setLogic1(true);
w2p.setLogic2(true);
w2p.setLogic3(true);
w2p.setLogic4(true);
w2p.setLogic5(false);
w2p.setNum5(7);
w2p.setLogic6(true);
w2p.build().writeTo(clientSocket.getOutputStream());
I have the following code for C++ (which acts as a server):
//Protobuf Setup Variables
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[1024];
struct sockaddr_in serv_addr, cli_addr;
int n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
std::cout << "Error Opening Socket!" << std::endl;
exit(1); //error
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
std::cout << "Error on Binding!" << std::endl; ;
exit(1); //error
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
std::cout << "ERROR on accept" << std::endl;
exit(1);
}
/* Clear Buffer and Read Message from Client */
bzero(buffer,1024);
n = read(newsockfd,buffer,1023);
std::cout << "n: " << n << std::endl;
if (n < 0){
std::cout << "Error Reading From Socket!" << std::endl;
}
/* Translate Shoreside to Pi Message */
std::string inputStr = std::string(buffer);
package_name::WinToPi w2p;
w2p.ParseFromString(inputStr);
With a static message, I am able to receive the appropriate number of bytes and values. With this, I moved to having values change dynamically on the Java side. However, it appears that on the c++ side, I will receive the correct number of bytes but the values will not have changed for a majority of the variables (only the first few). When I check the packaged and transmitted Google Protocol Buffer message on the Java side, it appears that I am sending the correct values. Is there a better approach for receiving a Google Protocol Buffer message in c++?
Your biggest problem seems to be this:
std::string inputStr = std::string(buffer);
When you construct a string like that - from a const char* - it will look for the first NUL as the terminator. You should instead use...
std::string inputStr = std::string(buffer, n);
...which will ensure the entire chunk of received data is stored into the string.
Another problem:
read on a socket may return whatever's sent over multiple calls, so you should always adopt a convention for working out when to stop reading (e.g. a fixed number of bytes known to client and sender - perhaps from a structure size, or a sentinel character or sequence such as newline or NUL, or a fixed-sized length prefix)
this is a natural consequence of buffering over the stream: say your client app calls write/send thrice while the OS is too busy to actually get any of the data into a network packet: when it does do so it may be able to fit the first and half the second "write" into one packet, then send the rest of the second along with the third in another; if the receiver expects each read to read the start of a multi-byte logical message, they're in for a shock
As for better approaches, for some small casual use I've found boost::asio makes for very concise, clear code and is a pleasure to use... lots of docs, examples, tutorials online.
I am trying to set up a simple Boost ASIO server with a single Java client.
I am able to send and successfully receive strings between the two. However, when I try to send double values, only garbage comes out on the other end.
Below is stand alone code that shows my basic setup (with a C++ Boost ASIO server and a Java client). When they are run, they do the following four sequential tasks:
The client sends a string to the server, which is successfully received and printed out.
The server sends a string to the client, which is successfully received and printed out.
The client sends a double value to the server, which is received but does NOT print out
correctly.
The server sends a double value to the client, which is received but does NOT print out
correctly.
Does anyone know what I am doing wrong? I am admittedly very new to networking (and Java). I have been through the Boost ASIO documentation and examples but to know avail.
C++ Boost ASIO server code:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>
using boost::asio::ip::tcp;
int main()
{
unsigned short const PORT = 19876;
try
{
boost::asio::io_service ioService;
tcp::acceptor acceptor(ioService, tcp::endpoint(tcp::v4(), PORT));
while (true)
{
// Listen for clients
std::cout << "Listening for client..." << std::endl;
tcp::socket socket(ioService);
acceptor.accept(socket);
std::cout << "Client heard..." << std::endl;
size_t len;
// Receive string from client and print it out
boost::array<char, 128> cBuf;
len = socket.read_some(boost::asio::buffer(cBuf, sizeof(cBuf)));
std::cout.write(cBuf.data(), len);
// Send string to client
std::string message = "Server string to send to client\n";
boost::asio::write(socket, boost::asio::buffer(message));
// Receive double from client and print it out
double dVal1 = -1.0;
char * p_dVal1 = reinterpret_cast<char *>(&dVal1);
len = socket.read_some(boost::asio::buffer(p_dVal1, sizeof(double)));
std::cout << dVal1<< std::endl; // prints out garbage
// Send double to client
double dVal2 = 6.28;
char const * p_dVal2 = reinterpret_cast<char const *>(&dVal2);
boost::asio::write(socket, boost::asio::buffer(p_dVal2, sizeof(double)));
}
}
catch (std::exception & e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
Java client code:
import java.io.*;
import java.net.*;
public class Client
{
final static String HOST = "localhost";
final static int PORT = 19876;
public static void main(String[] args) throws IOException
{
Socket socket = new Socket(HOST, PORT);
// Send string to server
PrintWriter pos = new PrintWriter(socket.getOutputStream(), true);
pos.println("Client string to send to server");
// Receive string from server
BufferedReader bis =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bis.readLine());
// Send double value to server
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeDouble(3.14);
// Receive double from server
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println(dis.readDouble()); // prints out garbage
socket.close();
pos.close();
bis.close();
dos.close();
dis.close();
}
}
Thank you very much in advance!!!
Aaron
You need to use a lexical_cast, not a reinterpret_cast.
With reinterpret_cast, you're telling the compiler to literally interpret the double* bit pattern as a const char* bit pattern. Instead, your cast should create a new structure with ascii chars that represent the number in an ascii bit pattern.
Also, you should ensure that you're managing endianess. You should properly convert to and from network endianess on both the client and server. See this answer for additional information.
I have a C++ server and two clients (ruby and java).
Everything is running on a 64-bit linux-machine (java 1.7.0_17)
The ruby client is fully working, but the java version makes problems.
In Java I tried to send a String from the client to the server. Actually the Server received the entire String, but the server thinks there is still something more to receive.
The ruby client looks a little bit like this:
socket = TCPSocket.open(#options[:host],#options[:port])
test = "Hello, World"
socket.puts test
socket.shutdown 1
response = socket.gets
Everything here is working fine. The ruby client sends a string. The server receives that string and sends a reply.
The Java Version looks like:
String ip = "127.0.0.1";
int port = 6686;
java.net.Socket socket = new java.net.Socket(ip,port);
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
InputStreamReader in = new InputStreamReader(socket.getInputStream());
String msg = "Hello, world!";
//send
PrintWriter pw = new PrintWriter(out, true);
pw.print(msg);
pw.flush();
// I also tried: out.write(msg); out.flush(); nothing changed
//receive the reply
BufferedReader br = new BufferedReader(in);
char[] buffer = new char[300];
int count = br.read(buffer, 0, 300);
String reply = new String(buffer, 0, count);
System.out.println(reply);
socket.close();
On the other side there is a C++ Server:
string receive(int SocketFD) {
char buffer[SOCKET_BUFFER_SIZE];
int recv_count;
// empty messagestring
string message = "";
// empty buffer
memset(buffer, 0, sizeof(buffer));
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
/*if (recv_count == -1) {
cout << "failed." << endl;
break;
}*/
cout << recv_count << endl;
if (ECHO_SOCKETS) cout << "received: " << buffer << endl;
message.append(buffer);
memset(buffer, 0, sizeof(buffer));
if (ECHO_SOCKETS) cout << "message is now: " << message << endl;
}
return message;
}
The server output from the Java-message is:
13
received: Hello, world!
message is now: Hello, world!
and then nothing happens.
The problem is that:
recv(SocketFD, buffer, sizeof(buffer) - 1, 0)
is catched in an endless loop (or something like that).
If I kill the Java-client process or I type something like:
pw.print(msg);
out.close();
the output on the server side is:
_sending reply: "Request unrecognized/invalid" request="Hello, world!"
send reply success
now close connection
This output is right (except "send reply success"), but in case of adding:
out.close();
the client can't receive the reply of the server. Because the Socket is closed.
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:864)
at MyServer.writeMessage(MyServer.java:56)
at MyServer.test(MyServer.java:42)
at MyServer.main(MyServer.java:30)
Edit
I tried to call pw.flush(); and different delimiters like "\n", "\r", "\r\n" and "\n\r" but the server still thinks there is still something to read. I also tried to use DatagramSockets:
java.net.DatagramSocket dSocket = new java.net.DatagramSocket();
InetAddress address = InetAddress.getByName("localhost");
String msg = "Hello, world!";
byte[] buf = msg.getBytes();
java.net.DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 6686);
But the server can't accept the packet.
Solution
The ruby-client does something like a socket.shutdownOutput(); (ruby: socket.shutdown 1) after the call of puts. I changed the java-client-code:
out.write(msg);
socket.shutdownOutput();
and it works!
As #Charly said: I have to define a "protocol". In my case I'm not allowed to change any communication related code (in the server and the ruby-client) because this functionality is used by a another group of researchers. So I've to modify my java-client in that way, that it does the exact same things at the exact same time as the ruby-client (something like a protocol).
PrintWriter buffer (when autoflush is true) is only flushed by calling println or printf. Calling print may not flush the buffer (Javadoc). Try calling println or use a OutputStreamWriter directly and flush().
Be aware of using the right charset (You can set it up in OutputStreamWriter constructor).
Close the stream respectively flush it in a way like this:
DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
dataOut.writeUTF(s);
dataOut.flush();
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
if (recv_count == -1) {
I don't know what your problem is but this code is certainly nonsense. It is impossible for the inner test ever to succeed.