I am trying to make an andorid app that commuicates with my server via Unity 5.4. The Devices need to be in the same network to do so.
For that i am using System.Net.Sockets and a TcpClient to connect to my server. Everything works well when i run it out of the Editor, or build it as a Windows standalone.The communication between a pc hosting the service and a diffrent pc running the standalone is possible and working as intended. As soon as i build it as an .apk and install it on my smartphone i will get a SocketException. Also my phone is stuck loading for quite some time
Is using a TcpClient, is that possible on android with unity3d ?
The Exception i get is:
System.Net.Sockets.SocketException: Connection timed out
I made sure that both devices are in the same network, e.g. the Ip for my Pc hosting the server is 192.168.178.24 and the ip for my smartphone is 192.168.178.113.
The ports required are open and the firewall lets data through.
I am runnig this code in Unity:
private TcpClient client;
private StreamWriter writer;
void Start()
{
try
{
client = new TcpClient(AddressFamily.InterNetwork);
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Debug.Log(ipAddress.ToString());
client.Connect(ipAddress, 11000);
writer = new StreamWriter(client.GetStream());
Debug.Log("connected");
}
catch (ArgumentNullException ane)
{
Debug.Log(string.Format("ArgumentNullException : {0}", ane.ToString()));
}
catch (SocketException se)
{
Debug.Log(string.Format("SocketException : {0}", se.ToString()));
}
catch (Exception e)
{
Debug.Log(string.Format("Unexpected exception : {0}", e.ToString()));
}
}
i double checked if the Ip adress recieved from the player prefs is correct, it is.
Has someone an idea what causes it to not even establish a connection ? I tried Wireshark on my pc, it didn't show any incoming packages, so my guess is the mistake is sometimes during establishing the connection.
Here is an image for my Log output from the smartphone:
LogCat Output
Edit: Server Code
public class ServiceListener
{
public TcpListener Listener;
public void StartListening()
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = Array.Find<IPAddress>(ipHostInfo.AddressList, ipMatch => ipMatch.AddressFamily == AddressFamily.InterNetwork);
Listener = new TcpListener(ipAddress, 11000);
Listener.Start();
}
public void StopListening()
{
Listener.Stop();
}
}
static void Main()
{
ServiceListener currentListener = new ServiceListener();
currentListener.StartListening();
TcpClient currentClient = currentListener.Listener.AcceptTcpClient();
StreamReader reader = new StreamReader(currentClient.GetStream());
Console.WriteLine("Connected");
while (true)
{
byte[] messageBytes = new byte[1024];
if (!reader.EndOfStream)
{
string message = reader.ReadLine();
string[] messageParts = message.Split('|');
int xOffset = int.Parse(messageParts[0]);
int yOffset = int.Parse(messageParts[1]);
bool leftClick = bool.Parse(messageParts[2]);
bool rightClick = bool.Parse(messageParts[3]);
Console.WriteLine(string.Format("x:{0},y:{1},left:{2},right:{3}", xOffset, yOffset, leftClick, rightClick));
}
else
{
currentClient = currentListener.Listener.AcceptTcpClient();
reader = new StreamReader(currentClient.GetStream());
}
}
}
Is using a TcpClient, is that possible on android with unity3d ?
Yes, it is. It is very possible and should work.
Your problem is very likely to come from this line of code:
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Since your hosting server IP is 192.168.178.24. Hardcode the value for testing purposes to see if PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey) is returning an invalid IP Address.
Maybe something like:
IPAddress ipAddress = IPAddress.Parse("192.168.178.24");
Another thing to do in your server code is to put Application.runInBackground = true; in your Start() function. This will make sure that your server is running even when the Applciation is not on focus.
Finally, you are currently using synchronous server socket. When connecting, receiving data from the server, Unity will block/freeze until that operation completes. You should use asynchronous socket or run your server and client code in another Thread. This does not look like the current problem but you will run into it later on.
Related
My situation:
I'm trying to create an android app using unity that has a server running, so I can call the service from a PC.
However, when I try to connect to the server I get the error message:
SocketException: No connection could be made because the target machine actively refused it.
System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP, Boolean requireSocketPolicy)
System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP)
System.Net.Sockets.TcpClient.Connect (System.Net.IPEndPoint remote_end_point)
System.Net.Sockets.TcpClient.Connect (System.Net.IPAddress[] ipAddresses, Int32 port)
Doing ping on the IP Address is fine, so the host is reachable, as far as I know android devices don't have firewalls, so my guess it is a problem with the port.
Currently I'm trying to run the service on port 9096, which works if I just run the application in the editor. Is this a valid port for android?
If not, what would be a valid one?
Do you have any other ideas on what the problem could be?
Thank you.
Additional info:
The device is Google Tango and I want to use Thrift to create a server and access the location of the device from a windows coomputer.
========================================================
UPDATE: included code for server and client
public void startServerService()
{
try
{
TangoService.Processor processor = new TangoService.Processor(this);
serverTransport = new TServerSocket(9096);
server = new TThreadPoolServer(processor, serverTransport);
Debug.Log("Starting the server...");
server.Serve();
}
catch (UnityException e)
{
Debug.Log(e);
}
}
void startClient()
{
try{
TTransport transport = new TSocket(ipAddress, 9096);
transport.Open ();
TProtocol protocol = new TBinaryProtocol(transport);
client=new TangoService.Client(protocol);
}
catch(UnityException e)
{
Debug.Log(e);
}
}
Im making a lua script running at my pc, and need to connect from my android.
So in the lua script I just put this:
local socket = require 'socket'
local server = socket.tcp()
print("createdserver")
server:bind('*',7070)
print("binded")
while 1 do
server:listen(32)
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then client:send(line .. "\n") end
-- done with client, close the object
client:close()
end
And at android I got a really simple socket connection:
public Connection(String ip, int _port) {
//inMessage = new NetworkMessage();
buffer = new byte[16394];
try {
serverAddres = InetAddress.getByName(ip);
socket = new Socket(serverAddres, _port);
socketOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Connect", e.getMessage());
}
}
At android it just stays at "new Socket" and dont connect.
Im not familiar with lua but my understanding is that you are writing a new line to the socket and you want to receive on the Android side.
Normally if that is the case you need to get the inputStream not the output one since you are waiting for results. Furthermore you need to indefinitely (or till some conditions are met) to listen to the input stream for data on a separate thread (a standard in):
while(true){
if (inputStreamReader().read() != -1){
// do you processing
}
}
My notebook was changing its IP address so I couldnt reach it from the android, already solved!
I am trying to send data from my Android phone to my home-server by using sockets. My server runs Linux so I used Perl to code the script for my server. The connection works fine and I can send data to my client running on the phone.
Problem is, when I send something (first try was a simple string) to the server, I don't receive anything at the servers side. Everything works fine if I use telnet to send a string to the server.
I am sitting here for some time now and I looked if there was a similar question to mine and could not find any in which the problem is discussed for Android to Perl-script. Here is my code for the Android app:
try {
Socket socket = new Socket("192.168.178.22", 22222);
Statusinformation("connection with server succeed");
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Statusinformation(input.readLine());
OutputStream outstream =socket.getOutputStream();
PrintWriter out = new PrintWriter(outstream);
out.println("This is a test message from client on phone!\n");
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Statusinformation("connection unsucsessfull");
e.printStackTrace();
}
on my phone I receive this if i execute the above code:
connection with server succeed!
and on the server side I'm using this code to receive the string from socket clients:
use IO::Socket;
my $server = IO::Socket::INET -> new(
Proto => 'tcp',
LocalPort => 22222,
Listen => SOMAXCONN,
);
print "Server started..\n";
while (1) {
next unless my $conect = $server -> accept();
my $childconection = fork;
if ($childconection == 0) {
handle_connection($conect);
}
}
sub handle_connection
{
my $sock = shift;
my $client_message="";
my $client_addr = $sock -> peerhost;
print "connection: $client_addr connected\n";
print $sock "hi $client_addr, you are connected!\n";
while (1) {
open (Tempfile, '>>tempfile.txt');
while ($client_message = <$sock>) {
print Tempfile $client_message;
print $client_message;
}
close (Tempfile);
}
close($sock);
exit(0);
}
ok now I am a little ashamed.
I solved the problem by adding:
out.flush();
the flush() method assures that all pending data is send to the target and flushs the target.
I'm developing an Android real-time-data app that sends data (floats and ints) to a server on the local subnet via a TCP socket. The problem I'm facing is that after sending some data simultaneously the socket doesn't send anymore data at all. I debugged the app and it shows that data is being sent but doesn't show up on the server. After this happens if I close the connection the server doesn't even get the notification that the connection has been terminated which it should according to my design model. Meanwhile I get an exception on the app saying it can not write to a broken pipe. This tells me that the problem is with the app because I also did test using a desktop app and I can send huge amounts of data to the server and it gets delivered.
And please keep in mind that the data size I'm talking about here is 252 bytes per packet.
Here's my class I'm using. (This runs in an AsyncTask object )
public class Network
{
private Socket handle;
public static enum TASK
{
TASK_CONNECT, TASK_SEND, TASK_CLOSE
}
public Network()
{
}
public String lastError = "";
public boolean Connect(String host, int port)
{
try
{
lastError = "Connecting to server.";
handle = new Socket(host, port);
handle.setTcpNoDelay(true); //
handle.setSendBufferSize(SIZE_OF_PACKET); ///==> These don't seem to help at all
handle.setKeepAlive(true); ///
return true;
}catch(IOException e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
return false;
}
}
private void err(String e){
System.err.println(e);
}
private boolean SendPacket(byte buffer[])
{
OutputStream oStream = null;
err("sending: " + buffer.length + " bytes");
try
{
lastError = "Obtaining output stream.";
oStream = handle.getOutputStream();
lastError = "Error sending data.";
oStream.write(buffer);
oStream.flush();
return true;
}catch(Exception e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
}
return false;
}
public void Close()
{
try{ handle.close(); handle = null; }catch(Exception e){} // swallow exception
}
}
I send my data in a loop depending on how many numbers I have. I tried a Google search but didn't find anything relevant. Has anyone experienced this before? It's making me mad now.
EDIT: Wireshark shows incoming "red" packets that don't reach the desktop app (server)
Look at this picture.
You can see the first few have Len > 0 the red ones have 0.
I think it's time Google interfaced the USB so we can use it. At least that'd would have been my first option.
Should you not be calling oStream.close() after you flush the stream, given that you never use it again?
Also, you say that this is being run in an AsyncTask object. Is it possible that multiple threads could be attempting to send packets at the same time? If so, you might need some form of synchronisation around the SendPacket method.
Ok. I solved the issue by using UDP instead. Thank you all.
But I still didn't find the source of the problem.
I have written this code for pinging class C IP addresses on port 6789, the thread starts when I click on a button called PING. It will retrieve all IP addresses that has the port 6789 open. But what I need is to refresh (re-ping) every, let's say 5 seconds, and add IPs recently joined if exist and omit ones that leave the port. Unfortunately another issue appears. When I started the application the first iteration of the while (true) works perfectly, and it adds any IP that had the port 6789 open to the ArrayList ips_List and then display it on the ListView, and when another device joins the port, my phone will add it to the ips_List also. BUT in the second iteration after the Thread sleeps 5 seconds and then begins to re-ping the IPs from (x.x.x.1 - x.x.x.254) to see if another IP had joined the port when pinging to an IP previously pinged, the Socket will throw IOException (as written in the code).
Why is that happening?
Thread pingo = new Thread(new Runnable() {
public void run() {
while (true) {
if (readableNetmask.equals("255.255.255.0")) {
for (int i = 2; i <= 25; i++) {
String ip_address = readableIPAddress;
String oct1 = "", oct2 = "", oct3 = "", oct4 = "";
StringTokenizer stok = new StringTokenizer(
ip_address, ".");
while (stok.hasMoreTokens()) {
oct1 = stok.nextToken();
oct2 = stok.nextToken();
oct3 = stok.nextToken();
oct4 = stok.nextToken();
}
to_ping_ip = oct1 + "." + oct2 + "." + oct3
+ "." + String.valueOf(i);
if (pingAddress(to_ping_ip, 6789)) {
ips_List.add(to_ping_ip);
}
}
}
// delay 10 seconds, then re-ping
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
break;
}
handler.post(new UpdateIPListViewRunnable());
}
}
});
pingo.start();
PingAddress() function:
public boolean pingAddress(String ip, int port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), 200);
socket.close();
} catch (IOException e) {
return false;
}
return true;
}
List where addresses appear:
static public class UpdateIPListViewRunnable implements Runnable {
public void run() {
arrayAdapter.clear();
for (int i = 0; i < ips_List.size(); i++) {
arrayAdapter.add(ips_List.get(i));
arrayAdapter.notifyDataSetChanged();
}
ips_List.clear();
}
}
Your problem is likely in your atypical usage of the word "ping". Traditionally, this refers to sending an ICMP echo request, which does not involve connection state, but is also often not allowed to ordinary user IDs such as your application will run under.
You appear to be using a stateful TCP connection instead, and may be running into difficulty in if your server is not tuned to be able to accept rapid reconnects. So you may want to try testing your server using some other client. You could also have a problem in that TCP will keep trying to get the traffic through, so it won't quickly report network troubles. You may even be ending up with multiple attempts overlapping in time.
Your best solution though would probably be to switch from TCP, which is ill suited to this task, to UDP, which is probably a better match. UDP does not have connection state, and it's also unreliable in that no automatic retries are attempted. You should be able to find a UDB echo server and client type example with a web search.
Thank you #Chris Stratton ... and there is noway that I am changing to protocol to UDP since my project's structure is build over the TCP architecture ... now for my problem I finally FOUND the solution; in my app i have a ServerSocket that is used for pinging ... now considering there are two mobiles with the same app, if PING button clicked then it will ping the other device and and the other device will accept() the connection then close() it. Now on the first mobile it will iterates another time (while(true)) and ping the same device, but that device has the ServerSocket closed so it will returns false. For this is used a recursive thread that when a mobile 1 pings mobile 2, mobile 2 will close the ServerSocket and immediately calls the same thread so the ServerSocket is opened to other pings. I tried it and it worked very well :DDD
[#Experts: any enhancements for this solution!]
Recursive Thread:
static public class ReceivePingThread extends Thread {
public void run() {
try {
ServerSocket joinPort = new ServerSocket(6789, 100);
joinPort.accept();
joinPort.close();
ReceivePingThread ReceivePingThread = new ReceivePingThread();
ReceivePingThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}