C# server Socket to Android Socket over NAT - java

The Android app is behind a NAT (3G connection) , while the server is on a public IP.
The Android app can connect to the server socket and send data (via Socket/TCPclient on android) but the server cannot connect to the Android port because of the NATs
(server getting "... has failed to respond "ip_adress_of_android : port_that_is_open_and_listening_on_android".
Is there anyway to overcome this, or some parameters I can use in order for the server connection attempt to reach it's destination over the NATs without using a custom library? - or could you please point me to an easy to implement method, I don't have time to study and integrate a complicated 3rd party library
Here is a sample of how my server code works:
int port_server, port_android; // used to declare used ports by the server and android
Socket server_socket, client_socket; //sockets used to receive and send data
server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server_socket.Bind(new IPEndPoint(IPAddress.Any, port_server));
server_socket.Listen(0);
public void listen()
{
server_socket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void AcceptCallback(IAsyncResult AR)
{
client_socket = server_socket.EndAccept(AR);
buffer = new byte[client_socket.ReceiveBufferSize];
client_socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
private void ReceiveCallback(IAsyncResult AR)
{
listen(); // to continue listening to the port
// code that does something with the data
send_string("Take this"); // sends a string to android
}
public void send_string(string notif)
{
string ip_client = client_socket.RemoteEndPoint.ToString();
string ip_client2 = (ip_c.Split(':'))[0];
TcpClient client = new TcpClient(ip_client, port_android);
Byte[] notifi = System.Text.Encoding.ASCII.GetBytes(notif);
NetworkStream stream = client.GetStream();
stream.Write(notifi, 0, notifi.Length);
stream.Close();
client.Close();
}
I should note that they work both ways when on a LAN, so the code is working, I only need to modify is so that it can reach android targets over NATs.

Something like this
class Program
{
int port_server = 42424;
Socket server_socket;
public Program()
{
server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server_socket.Bind(new IPEndPoint(IPAddress.Any, port_server));
server_socket.Listen(0);
}
public void Listen()
{
while (true)
{
var client = server_socket.Accept();
var buffer = new byte[client.ReceiveBufferSize];
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), Tuple.Create(client, buffer));
}
}
private void ReceiveCallback(IAsyncResult AR)
{
var state = (Tuple<Socket, byte[]>)AR.AsyncState;
var client = state.Item1;
var buffer = state.Item2;
byte[] notifi = System.Text.Encoding.ASCII.GetBytes("Take this");
client.Send(notifi);
client.Close();
}
static void Main(string[] args)
{
var programm = new Program();
programm.Listen();
}
}
client part
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 42424));
client.Send(new byte[] {1, 2, 3}, SocketFlags.None);
byte[] bt = new byte[256];
client.Receive(bt, 256, SocketFlags.None);
}

Related

How to group 2 udp clients?

What i'm trying to do is group 2 clients and make them communicate with eachother. So if 2 clients are connected they would only be able to communicate with eachother and if a third client got connected it would not be able to communicate with the 2 other clients but it would create another group of 2 clients and so on... Right now if a client sends a message it send it over to all clients but i don't know how to make it work like described above. Messages are send from client by typing something in console.
server:
public class Server extends Thread{
public final static int PORT = 7331;
private final static int BUFFER = 1024;
private DatagramSocket socket;
private ArrayList<InetAddress> clientAddresses;
private ArrayList<Integer> clientPorts;
private HashSet<String> existingClients;
public Server() throws IOException {
socket = new DatagramSocket(PORT);
System.out.println("[SERVER] UDP server successfully launched on port " + PORT);
clientAddresses = new ArrayList<InetAddress>();
clientPorts = new ArrayList<Integer>();
existingClients = new HashSet<String>();
}
public void run() {
byte[] buf = new byte[BUFFER];
while (true) {
try {
//resets buffer so only new messages get displayed
Arrays.fill(buf, (byte) 0);
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String content = new String(buf, buf.length);
InetAddress clientAddress = packet.getAddress();
int clientPort = packet.getPort();
String id = clientAddress.toString() + "," + clientPort;
if (!existingClients.contains(id)) {
existingClients.add(id);
clientPorts.add(clientPort);
clientAddresses.add(clientAddress);
}
System.out.println(id + " : " + content);
byte[] data = (id + " : " + content).getBytes();
for (int i = 0; i < clientAddresses.size(); i++) {
InetAddress cl = clientAddresses.get(i);
int cp = clientPorts.get(i);
packet = new DatagramPacket(data, data.length, cl, cp);
socket.send(packet);
}
} catch (Exception e) {
System.err.println(e);
}
}
}
public static void main(String args[]) throws Exception {
Server s = new Server();
s.start();
}
}
clients:
public class Client implements Runnable {
public static void main(String args[]) throws Exception {
String host = "127.0.0.1";
DatagramSocket socket = new DatagramSocket();
//handles the receiving part for every client (incoming packets to clients)
MessageReceiver r = new MessageReceiver(socket);
Client s = new Client(socket, host);
Thread rt = new Thread(r);
Thread st = new Thread(s);
rt.start();
st.start();
}
public final static int PORT = 7331;
private DatagramSocket sock;
private String hostname;
Client(DatagramSocket s, String h) {
sock = s;
hostname = h;
}
//sending clients socket to server
private void sendMessage(String s) throws Exception {
//getting bytes from message
byte buf[] = s.getBytes();
//getting hostname from server
InetAddress address = InetAddress.getByName(hostname);
//setting up packet
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, PORT);
//sending packet to server
sock.send(packet);
}
public void run() {
//connected boolean is used to send a greetings message once for every new client that has joined
boolean connected = false;
do {
try {
sendMessage("GREETINGS");
connected = true;
} catch (Exception e) {
}
} while (!connected);
//reads from the console
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
while (!in.ready()) {
Thread.sleep(100);
}
//sends message from console to server
sendMessage(in.readLine());
} catch (Exception e) {
System.err.println(e);
}
}
}
}
//this class handles receiving part of clients
class MessageReceiver implements Runnable {
DatagramSocket sock;
byte buf[];
MessageReceiver(DatagramSocket s) {
sock = s;
buf = new byte[1024];
}
public void run() {
while (true) {
try {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
sock.receive(packet);
String received = new String(packet.getData(), 0,
packet.getLength());
System.out.println(received);
} catch (Exception e) {
System.err.println(e);
}
}
}
}
What youre trying is a message broadcast or a message-repeater-client.
broadcasting is implemented on network layer (using brodcast the local network broadcast adress).
And if you implementing it that way, you'll flood your network, when you have more than 2 clients. Best regards to your network admin. ;-)

UDP communication between Java and C#

I'm trying to communicate a Java program with a C# one but it's not working.
The code is really basic, here it is:
This is the Java client
static InetAddress ip;
static int port = 10000;
public static void main(String args[]) {
try {
ip = InetAddress.getByName("127.0.0.1");
DatagramSocket socket = new DatagramSocket(port, ip);
byte[] sendData = new byte[1024];
sendData = "Hola".getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
socket.send(sendPacket);
socket.close();
} catch (Exception e) {
}
}
And here it is the C# server
static UdpClient client;
static IPEndPoint sender;
void Start () {
byte[] data = new byte[1024];
string ip = "127.0.0.1";
int port = 10000;
client = new UdpClient(ip, port);
sender = new IPEndPoint(IPAddress.Parse(ip), port);
client.BeginReceive (new AsyncCallback(recibir), sender);
}
static void recibir(IAsyncResult res){
byte[] bResp = client.EndReceive(res, ref sender);
//Convert the data to a string
string mes = Encoding.UTF8.GetString(bResp);
//Display the string
Debug.Log(mes);
}
The c# server is a Unity file, I mean, I execute it from Unity, so Start is the first method called.
I would like them to communicate through port 10000 (or any ohter one) in my computer, java's main and c#'s start seem to be executed but the callback is never called.
Any ideas of why it isn't working? Thank you all.
BeginReceive() is non-blocking. Your program terminates before it can receive anything. Either use Receive() or put a busy-waiting-loop at the end of the server code.
I've solved it, in the Java client new DatagramSocket() must be called without any argument, and in the c# server new UdpClient(port); must be called only with the port.

Why I can't view my UDP received Image in Android Studio?

I succeeded in sending a string from Android Studio Java UDP Client to Visual Studio C# UDP Server, and a response back from the Server to the Client.
Now I am trying to send an Image back from the server instead of a string response. So on client button click, I am supposed to get an Image back from the server. No syntax errors and no weird behavior. It's just nothing happens and I can't seem to see the received image on my ImageView and when I step over it my final Bitmap ReceivedImage is null
Do I need to convert into something other than Bitmap? Is this the right way? Maybe something else.. Can anyone help me point out my mistake? Thanks
C# Server:
class UdpServer
{
static void Main(string[] args)
{
byte[] dataReceived = new byte[1024];
UdpClient serverSocket = new UdpClient(15000);
string path = "C:\\Users\\kkhalaf\\Desktop\\Capture.PNG"; // image path
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); // prepare
BinaryReader br = new BinaryReader(fs); // prepare
byte[] dataToSend = br.ReadBytes(Convert.ToInt16(fs.Length)); //Convert image to byte[]
int i = 0;
while (true) // this while for keeping the server "listening"
{
Console.WriteLine("Waiting for a UDP client..."); // display stuff
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); // prepare
dataReceived = serverSocket.Receive(ref sender); // receive packet
string stringData = Encoding.ASCII.GetString(dataReceived, 0, dataReceived.Length); // get string from packet
Console.WriteLine("Response from " + sender.Address); // display stuff
Console.WriteLine("Message " + i++ + ": " + stringData + "\n"); // display client's string
// Here I am sending back
serverSocket.Send(dataToSend, 8, sender);
}
}
}
Java Client: On button click this function gets called to send-receive-display
public void SendUdpMsg(final String msg)
{
Thread networkThread = new Thread() {
// No local Host 127.0.0.1 in Android
String host = "192.168.200.3"; // Server's IP
int port = 15000;
DatagramSocket dsocket = null;
public void run() {
try {
// Get the Internet address of the specified host
InetAddress address = InetAddress.getByName(host);
// wrap a packet
DatagramPacket packetToSend = new DatagramPacket(
msg.getBytes(),
msg.length(),
address, port);
// Create a datagram socket, send the packet through it.
dsocket = new DatagramSocket();
dsocket.send(packetToSend);
// Here, I am receiving the response
byte[] buffer = new byte[1024]; // prepare
DatagramPacket packetReceived = new DatagramPacket(buffer, buffer.length); // prepare
dsocket.receive(packetReceived); // receive packet
byte[] buff = packetReceived.getData(); // convert packet to byte[]
final Bitmap ReceivedImage = BitmapFactory.decodeByteArray(buff, 0, buff.length); // convert byte[] to image
runOnUiThread(new Runnable() {
#Override
public void run() {
// this is executed on the main (UI) thread
final ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(ReceivedImage);
}
});
dsocket.close();
} catch (Exception e) {
e.printStackTrace();
}//catch
}//run
};// Networkthread
networkThread.start();//networkThread.start()
}
Isn't much of an answer, but since I can't comments yolo
You should use TCP, it is so much better. Using UDP, I even loose data when it is 400 bytes.
It might be
serverSocket.Send(dataToSend, 8, sender);
Change it to
serverSocket.Send(dataToSend, dataToSend.Length, sender);
Also, try first sending the length of the image (dataToSend.Length) to the client, then have the client use the length you sent it to create a byte array. Kind like
byte[] buffer = new byte[recievedLengthOfImage]

Single Threaded Server Implementation to Multi Threaded

Guys I want to convert my server implementation into multi thread so that it can handle multiple requests. Basically the server is connected with an android application and it is recieving an image from android application. I want to add a thread so that it can handle multiple requests and the thread should start when the request is recieved. Kindly help me out.
This is the Server Code.
public static void main(String[] args) throws UnknownHostException, IOException, MatlabInvocationException, MatlabConnectionException {
while (true) {
try {
serverSocket = new ServerSocket(4001); // Server socket
} catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
System.out.println("Server started. Listening to the port 4001");
clientSocket = serverSocket.accept();
DataInputStream inputFromClient = new DataInputStream(clientSocket.getInputStream());
int count = inputFromClient.readInt();
int available = inputFromClient.available();
System.out.println("Length of Image in Bytes:" + count);
System.out.println("available:" + available);
image = new byte[count];
inputFromClient.readFully(image);
System.out.println(image.length);
System.out.println(image);
final BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(image));
ImageIO.write(bufferedImage, "jpg", new File("image.jpg"));
System.out.println("Image has been wriiten in the directory.");
MatlabProxyFactory mpf = new MatlabProxyFactory();
MatlabProxy proxy = mpf.getProxy();
proxy.eval("conclusion=DetectColorL");
Object[] obj = proxy.returningEval("conclusion", 1);
String Message = obj[0].toString();
DataOutputStream outTo = new DataOutputStream(clientSocket.getOutputStream());
outTo.writeUTF(Message.toString());
System.out.println(Message);
proxy.disconnect();
serverSocket.close();
To make it multithreaded you want to be able to have multiple clients connected at the same time, to handle multiple requests instead of one at a time.
To do so, your server will have to permanently accept new clients.
public static void main(String[] args) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(4001); // Server socket
System.out.println("Server started. Listening to the port 4001");
while (true) {
// Always accept new clients
Socket clientSocket = serverSocket.accept();
new RequestHandlingClass(clientSocket).start(); // Make a new thread and call it's run procedure
}
} catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
}
Now our server accepts multiple clients we have to implement the RequestHandlingClass class. You want that class to listen for client requests and handle them.
public class RequestHandlingClass() extends Thread {
Socket clientSocket;
DataInputStream inputFromClient;
RequestHandlingClass(Socket clientSocket) {
this.clientSocket = clientSocket;
this.inputFromClient = new DataInputStream(clientSocket.getInputStream());
// ...
}
public void run() {
// Handle client requests
}
}
Based on your question I suppose you want to execute the "image handling" code in the run method.

java-udp programming -sending message from server to the client

I made connection between server and client properly and i send message from client to the server,but how can i send messages from server to client.I mean how can i make server act like a client too.i tried to copy the client methods to the another class that server can invoke.but i couldnt then i tried to create a new package to use the client code in server class.any advices?
ps:Sorry about my english.
public class Entrance_Server extends JFrame{
JButton buton = new JButton("Create");
JButton buton2 = new JButton("Join");
JPanel butonpanel = new JPanel();
DatagramSocket sockServer = null;
DatagramSocket sockClient = null;
int port = 7777;
String s;
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
public Entrance_Server() {
setLayout(new GridLayout(2,1));
add(buton);
add(buton2);
buton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Choosing c = new Choosing();
c.start();
System.out.println("Server socket created. Waiting for incoming data...");
}
});
buton2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Choosing c = new Choosing();
c.start();
}
});
}
public static void main(String[] args){
Entrance_Server e = new Entrance_Server();
e.setSize(500,350);
e.setTitle("Welcome");
e.setLocationRelativeTo(null);
e.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
e.setVisible(true);
e.connect();
}
public void connect (){
try{
sockServer = new DatagramSocket(7777);
byte[] buffer = new byte[65536];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
while(true)
{
sockServer.receive(incoming);
byte[] data = incoming.getData();
String s = new String(data, 0, incoming.getLength());
//echo the details of incoming data - client ip : client port - client message
System.out.println(incoming.getAddress().getHostAddress() + " : " + incoming.getPort() + " - " + s);
s = "OK : " + s;
DatagramPacket dp = new DatagramPacket(s.getBytes() , s.getBytes().length , incoming.getAddress() , incoming.getPort());
sockServer.send(dp);
Entrance_Client_in_Server ec = new Entrance_Client_in_Server();
ec.connectc();
}
}catch(IOException i){
System.err.println("IOException " + i);
}
}
}
On your client u need to wait on the server response by using socket.Receive()
You can identify a client after he has send a packet to the server like you are doing. You can then indentify the client like this:
InetAddress address = packet.getAddress();
int port = packet.getPort();
And use it to send a packet back to the client, which will read the response using the socket.Receive();
For further information about Client/Server connection using UDP DatagramSockets check
Client-Server Datagram sockets

Categories