I'm trying to create an UDP server with two slots per new instance of the game and clients.
It has to be UDP cause of the game mechanics. I wrote this:
public class Server {
private static HashSet<Integer> ports = new HashSet<Integer>(); // these are player's IDs
static ArrayList<InetAddress> addresses = new ArrayList<InetAddress>();
public static boolean player1_active = false, player2_active = false;
public static PlayerCredits p1, p2, temp;
public static void main(String[] args) throws Exception {
// The default port
int serverport = 8888;
DatagramSocket udpServerSocket = new DatagramSocket(serverport);
DatagramPacket sendpacket;
System.out.println("Server started...\n");
while(true)
{
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
udpServerSocket.receive(receivePacket);
String clientMessage = (new String(receivePacket.getData())).trim();
System.out.println("Client Connected - Socket Address: " + receivePacket.getSocketAddress());
System.out.println("Client message: \"" + clientMessage + "\"");
InetAddress clientIP = receivePacket.getAddress();
addresses.add(clientIP);
System.out.println("Client IP Address & Hostname: " + clientIP + ", " + clientIP.getHostName() + "\n");
// Get the port number which the recieved connection came from
int clientport = receivePacket.getPort();
System.out.println("Adding "+clientport);
ports.add(clientport);
// Response message
String returnMessage = clientMessage.toUpperCase();
System.out.println(returnMessage);
// Create an empty buffer/array of bytes to send back
byte[] sendData = new byte[1024];
temp = new PlayerCredits(clientport, clientIP);
if(!player1_active){
p1 = new PlayerCredits(clientport, clientIP);
player1_active = true;
}
if(temp.port != p1.port && temp.ad != p1.ad)
if(!player2_active){
p2 = new PlayerCredits(clientport, clientIP);
player2_active = true;
}
DatagramPacket sendPacket;
if(p2 == null){
String awaiting = "WAITING FOR SECOND PLAYER";
sendData = awaiting.getBytes();
sendPacket= new DatagramPacket(sendData, sendData.length, p1.ad, p1.port);
udpServerSocket.send(sendPacket);
}
else{
String awaiting = "SECOND PLAYER INCOMING";
sendData = awaiting.getBytes();
if(p2!=null){
sendPacket = new DatagramPacket(sendData, sendData.length, p2.ad, p2.port);
udpServerSocket.send(sendPacket);
}
sendPacket = new DatagramPacket(sendData, sendData.length, p1.ad, p1.port);
udpServerSocket.send(sendPacket);
}
}
}
public static class PlayerCredits{
int port;
InetAddress ad;
public PlayerCredits(int p, InetAddress a){
this.port = p;
this.ad = a;
}
}
For now I have two people connected - but as you will probably say - it's WRONG. I need to somehow implement every player on the Multisocket or something (or connect them via TCP and then listen on a new thread with a new datagram).
As I know, the best way is to create a listener server (TCP) on a main thread - accept connections and pass them to 'Player's constructors' and in Player's class make the whole fun.
If there is someone that could help and tell me, how it should be done like in 3 steps like (I don't need code):
Connection with TCP
Create new threads with players and listen on UDP
Start the game when 2 players are connected
Also, how to stop the 'third connection' and redirect it to a new game instance? (cause it's 1v1).
Related
I want to create a UDP socket to receive data from Local Endpoint.
I do not know the Remote Port where data come from, that's why I thought I would use ReceiveAsync. But it does not work.
I give my code right now and any advice would be useful:
public class Program
{
ManualResetEvent clientDone;
Socket socket;
public static void Main(string[] args)
{
clientDone = new ManualResetEvent(false);
socket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localIPEP = new IPEndPoint( IPAddress.Any, 0);
socket.Bind( (EndPoint) localIPEP);
while (listening)
Receive();
}
string Receive()
{
string response;
byte[] recvData = new byte[24];
if (socket != null)
{
SocketAsyncEventArgs ae = new SocketAsyncEventArgs();
ae.SetBuffer(recvData, 0, recvData.Length);
// callback
ae.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceivedData(e);
break;
}
clientDone.Set();
});
clientDone.Reset();
Console.WriteLine("Local EndPoint: " + ((IPEndPoint)socket.LocalEndPoint).ToString());
socket.ReceiveAsync(ae);
clientDone.WaitOne(1000);
}
return response;
}
}
P.S. I work on Linux .Net Core
I have an application within Unity3D (acting as a server) that receives messages from an exterior application (single client) with the following structure:
number(float) number(float) number(float)
The first two numbers represent the local position (x,z axis) and the last one a rotation value (y axis).
The goal is to use this data to update the Camera gameobject position (using the LoadPositions method) within the game scene. From what I've read manipulating gameobjects while outside Unity's main thread is not possible.
With that being said how can I change from and to Unity main thread so that I can both listen for messages and update the gameobjects position.
Also, anyone happens to know of a working example of a simple TCP Server in Unity without having to resort to threads?
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System;
using System.Text;
using System.Collections.Generic;
public class ProxyThreadServer : MonoBehaviour {
float x;
float z;
float rot;
Vector3 updatePos;
Vector3 updateRot;
string ip_address = "127.0.0.1";
string msgReceived;
string[] words;
int wordsNum;
int port = 8000;
int numSurf;
int jumpInterval;
Thread listen_thread;
TcpListener tcp_listener;
Thread clientThread;
TcpClient tcp_client;
bool isTrue = true;
// Use this for initialization
void Start ()
{
IPAddress ip_addy = IPAddress.Parse(ip_address);
tcp_listener = new TcpListener(ip_addy, port);
listen_thread = new Thread(new ThreadStart(ListenForClients));
listen_thread.Start();
}
private void ListenForClients()
{
this.tcp_listener.Start();
while(isTrue == true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcp_listener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
Debug.Log("Got client " + client);
}
}
private void HandleClientComm(object client)
{
tcp_client = (TcpClient)client;
NetworkStream client_stream = tcp_client.GetStream();
byte[] message = new byte[4096];
int bytes_read;
while(isTrue == true)
{
bytes_read = 0;
try
{
//blocks until a client sends a message
bytes_read = client_stream.Read(message, 0, 4096);
//Debug.Log(message);
}
catch (Exception e)
{
//a socket error has occurred
Debug.Log(e.Message);
break;
}
if(bytes_read == 0)
{
//client has disconnected
Debug.Log("Disconnected");
tcp_client.Close();
break;
}
ASCIIEncoding encoder = new ASCIIEncoding();
Debug.Log(encoder.GetString(message,0,bytes_read));
msgReceived = encoder.GetString(message,0,bytes_read);
LoadPositions(msgReceived);
}
if(isTrue == false)
{
tcp_client.Close();
Debug.Log("closing tcp client");
}
}
void OnApplicationQuit()
{
try
{
tcp_client.Close();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
// You must close the tcp listener
try
{
tcp_listener.Stop();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}
void LoadPositions(string positions){
// Split string on spaces. This will separate all the words.
words = positions.Split(' ');
wordsNum = words.Length;
for (int i = 0; i <= wordsNum; i++) {
x = float.Parse(words[0], System.Globalization.CultureInfo.InvariantCulture);
z = float.Parse(words[1], System.Globalization.CultureInfo.InvariantCulture);
rot = float.Parse(words[2], System.Globalization.CultureInfo.InvariantCulture);
Debug.Log("Reading position: " + "x: " + x + " z: " + z + " yRot: " + rot);
updatePos = new Vector3(x, this.gameObject.transform.position.y, z);
this.gameObject.transform.position = updatePos;
updateRot = new Vector3(this.gameObject.transform.rotation.x, rot / 4, this.gameObject.transform.rotation.z);
this.transform.localEulerAngles = updateRot;
//UpdateCameraMatrix();
//StartCoroutine(UpdateSurfs());
}
}
}
While I haven't tried to do something quite like this before, assuming the limitations do exist as you mentioned, my approach would be to use a queue to store the messages then process them in the order they came in on the unity thread. So instead of calling LoadPositions when it comes it, add it to a queue
pendingMessages.Enqueue(msgReceived);
Then in the update method you process it:
void Update()
{
while (pendingMessages.Count() > 0)
LoadPositions(pendingMessages.Dequeue());
}
You can use .NET's Async TCP. It's based on callback delegates. (Working with it is a bit tricky though)
I am studying Spark streaming to process real time data, and I built the example wordCount of spark streaming, and I can run the example after:
/bin/run-example org.apache.spark.streaming.examples.JavaNetworkWordCount local[2] localhost 9999
And if I run nc -L -p 9999 in another terminal, then I can type letters in this terminal, and the example can receive the letters and give the right result.
But I developed a Java socket client to send content to 9999 port - why can't the example receive it? I think the example just monitor the 9999 port, and receive anything from the port.
Here is the Java code:
File file = new File("D:\\OutputJson.dat");
long l = file.length();
socket = new Socket();
boolean connected = false;
while (!connected) {
//not stop until send successful
try {
socket.connect(new InetSocketAddress("localhost", 9999));
connected = true;
System.out.println("connected success!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("connected failed!");
Thread.sleep(5000);
}
}
dos = new DataOutputStream(socket.getOutputStream());
fis = new FileInputStream(file);
sendBytes = new byte[1024];
while ((length = fis.read(sendBytes, 0, sendBytes.length)) > 0) {
sumL += length;
System.out.println("sent:" + ((sumL / l) * 100) + "%");
dos.write(sendBytes, 0, length);
dos.flush();
}
if (sumL == l) {
bool = true;
}
This Java function is always returning the following error:
java.net.SocketException: Socket closed
I have developed another Java class to receive the data from this sending socket, and it works fine, why the can't spark receive with this one?
From memory I think I used a ServerSocket. The code was something like:
public void sendMsg(String msg) throws IOException {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(port);
clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.write(msg);
out.flush();
out.close();
} finally {
try {
clientSocket.close();
serverSocket.close();
} finally {
clientSocket = null;
serverSocket = null;
}
}
}
This is the code for my client and server.
class Client1
{
Client1(int no)
{
try
{
String message;
message="Hello this is client "+no;
byte[] b =message.getBytes();
DatagramPacket dp = new DatagramPacket(b, b.length,InetAddress.getLocalHost(),3700);
DatagramSocket sender = new DatagramSocket();
sender.send(dp);
}catch (Exception e)
{
System.out.println("client shutdown");
}
}
}
Then my server class is
class Server1
{
int cnt=0;
String s1;
Server1()
{
try {
byte[] buffer = new byte[65536];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
DatagramSocket ds = new DatagramSocket(3700);
ds.receive(incoming);
byte[] data = incoming.getData();
String s = new String(data, 0, incoming.getLength());
System.out.println("Port" + incoming.getPort() + " on " + incoming.getAddress() + " sent this message:");
System.out.println(s.toUpperCase());
}
catch (IOException e)
{
System.err.println(e);
}
}
}
Then my runnable implementation is
class prothread implements Runnable {
//long time=0;
//int portno;
int flag=0; // this is to differentiate between a server and client
private String capitalizedSentence;
prothread(long l)
{
if(l==1)
{ // it is a server
flag=1;
}
else
{
flag=(int) l;
}
}
#Override
public void run(){
// TODO Auto-generated method stub
System.out.println("Starting thread");
if(flag==1)// Code for server
{
Server1 s=new Server1();
}
else // code for client
{
Client1 c=new Client1(flag);
}
}
}
Finally the class which deploys this client and server is
public class Samplepro31 {
public static void main(String[] args) {
// First i'm going to create a server and then clients for it
int i=1;
int cnt=0;
prothread[] p;
Thread[] th;
Random r =new Random();
// Array has been declared
p=new prothread[10];// Memory allocated to it
th= new Thread[1000];
p[0]=new prothread(1);
cnt=1;
//p[0].setportno(cnt);
th[0]=new Thread(p[0]);
th[0].start();
while(cnt<3)
{
p[cnt]=new prothread(cnt);
// here send the port number
th[cnt]=new Thread(p[cnt]);
//p[cnt1].setportno(cnt1);
th[cnt].start();
cnt++;
}
}
}
So problem I'm having is one server and only one client is running at a time
instead 2 clients should be running the o/p i'm getting is :
Starting thread
Starting thread
Starting thread
Inside clinet's constructor 2
java.net.BindException: Address already in use: Cannot bind
HELLO THIS IS CLIENT 2
So can anybody tell me what I'm doing wrong?
Don't bind the client to any particular port. Let the implementation select an available port to bind to.
I'm trying to implement a simple TCP connection between Client/Server. I made the Server multithreaded so that it can take either multiple requests (such as finding the sum, max, min of a string of numbers provided by the user) from a single client or accept multiple connections from different clients. I'm running both of them on my machine, but the server doesn't seem to push out an answer. Not sure what I'm doing wrong here --
public final class CalClient {
static final int PORT_NUMBER = 6789;
public static void main (String arg[]) throws Exception
{
String serverName;
#SuppressWarnings("unused")
String strListOfNumbers = null;
int menuIndex;
boolean exit = false;
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter host name...");
System.out.print("> ");
serverName = inFromUser.readLine();
Socket clientSocket = new Socket(serverName, PORT_NUMBER);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//outToServer.writeBytes(serverName + '\n');
System.out.println("");
System.out.println("Enter 1 to enter the list of numbers");
System.out.println("Enter 2 to perform Summation");
System.out.println("Enter 3 to calculate Maximum");
System.out.println("Enter 4 to calculate Minimum");
System.out.println("Enter 5 to Exit");
while (!exit) {
System.out.print(">");
menuIndex = Integer.parseInt(inFromUser.readLine());
if (menuIndex == 1) {
System.out.println("Please enter the numbers separated by commas.");
System.out.print(">");
strListOfNumbers = inFromUser.readLine();
outToServer.writeBytes("List" + strListOfNumbers);
//continue;
}
else if (menuIndex == 2) {
outToServer.writeBytes("SUM");
System.out.println(inFromServer.readLine());
}
else if (menuIndex == 3) {
outToServer.writeBytes("MAX");
System.out.println(inFromServer.readLine());
}
else if (menuIndex == 4) {
outToServer.writeBytes("MIN");
System.out.println(inFromServer.readLine());
}
else if (menuIndex == 5) {
outToServer.writeBytes("EXIT");
exit = true;
}
}
}
}
public final class CalServer
{
static final int PORT_NUMBER = 6789;
public static void main(String[] args) throws IOException
{
try {
ServerSocket welcomeSocket = new ServerSocket(PORT_NUMBER);
System.out.println("Listening");
while (true) {
Socket connectionSocket = welcomeSocket.accept();
if (connectionSocket != null) {
CalRequest request = new CalRequest(connectionSocket);
Thread thread = new Thread(request);
thread.start();
}
}
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
final class CalRequest implements Runnable
{
Socket socket;
BufferedReader inFromClient;
DataOutputStream outToClient;
TreeSet<Integer> numbers = new TreeSet<Integer>();
int sum = 0;
public CalRequest(Socket socket)
{
this.socket = socket;
}
#Override
public void run()
{
try {
inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
outToClient = new DataOutputStream(socket.getOutputStream());
while(inFromClient.readLine()!= null) {
processRequest(inFromClient.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void processRequest(String string) throws IOException
{
String strAction = string.substring(0,3);
if (strAction.equals("LIS")) {
String strNumbers = string.substring(5);
String[] strNumberArr;
strNumberArr = strNumbers.split(",");
// convert each element of the string array to type Integer and add it to a treeSet container.
for (int i=0; i<strNumberArr.length; i++)
numbers.add(new Integer(Integer.parseInt(strNumberArr[i])));
}
else if (strAction.equals("SUM")) {
#SuppressWarnings("rawtypes")
Iterator it = numbers.iterator();
int total = 0;
while (it.hasNext()) {
total += (Integer)(it.next());
}
}
else if (strAction.equals("MAX")) {
outToClient.writeBytes("The max is: " + Integer.toString(numbers.last()));
}
else if (strAction.equals("MIN")) {
outToClient.writeBytes("The max is: " + Integer.toString(numbers.first()));
}
}
}
Since you are using readLine(), I would guess that you actually need to send line terminators.
My experience with TCP socket communications uses ASCII data exclusively, and my code reflects that I believe. If that's the case for you, you may want to try this:
First, try instantiating your data streams like this:
socket = new Socket (Dest, Port);
toServer = new PrintWriter (socket.getOutputStream(), true);
fromServer = new BufferedReader (new InputStreamReader
(socket.getInputStream()), 8000);
The true at the end the printWriter constructor tells it to auto flush (lovely term) the buffer when you issue a println.
When you actually use the socket, use the following:
toServer.println (msg.trim());
resp = fromServer.readLine().trim();
I don't have to append the \n to the outgoing text myself, but this may be related to my specific situation (more on that below). The incoming data needs to have a \n at its end or readLine doesn't work. I assume there are ways you could read from the socket byte by byte, but also that the code would not be nearly so simple.
Unfortunately, the TCP server I'm communicating with is a C++ program so the way we ensure the \n is present in the incoming data isn't going to work for you (And may not be needed in the outgoing data).
Finally, if it helps, I built my code based on this web example:
http://content.gpwiki.org/index.php/Java:Tutorials:Simple_TCP_Networking
Edit: I found another code example that uses DataOutputStream... You may find it helpful, assuming you haven't already seen it.
http://systembash.com/content/a-simple-java-tcp-server-and-tcp-client/