Socket handling


photo

Recommended Posts

Hi Guys,

 

i have a Question to the Sockethandling.

 

Socket recvSocket;
Socket sndSocket;
int Connected = 0;
int init() 
{
   Logger::init();
   BuildingSystemLogger::init(); 
   sndSocket = new Socket("127.0.0.1",7654);
   recvSocket = new Socket("127.0.0.1",8654);
   sndSocket.connect();

   recvSocket.bind();
   recvSocket.listen(10);
   recvSocket.nonblock();
   return 1;
}

int update() {
     Socket s = new Socket();
     if (Connected == 0) 
     {
           Connected = recvSocket.accept(s);   

           if (Connected == 1) 
           {
               Logger::logger (0, "netzwerk::update()","verbunden" + Connected ); 
               Logger::logger (0, "netzwerk::update()","verbunden" + Connected );            
           }
     }

     if (Connected == 1) 
     {
           Logger::logger (0, "netzwerk::update()","123" );  
           string get = recvSocket.readLine();
           Logger::logger (0, "netzwerk::update()","123" );  
           Logger::logger (0, "netzwerk::update()",get );  
           int buf[1],old = '\n';
           while(1) {
     		if(recvSocket.read(buf,1) != 1)
                 {
                 Logger::logger (0, "netzwerk::update()","1" );  
                 break;                  
                 } 
     		if(buf[0] == '\r')
                 {
                 Logger::logger (0, "netzwerk::update()","2" );  
                 continue;     
                 } 
     		if(buf[0] == '\n' && old == '\n')
                 {
                 Logger::logger (0, "netzwerk::update()","2" );  
                 break;          
                 } 
     		old = buf[0];
      }
     }


return 1;
}

So i got the Log "Logger::logger (0, "netzwerk::update()","verbunden" + Connected ); " and on my Server-Programm i already got the message, that all Socktes have Connection.

 

But my Problem is, that i get not Messages on my ReceiverSocket, and i dont know why. Where is here my Failure, pls ?

 

Greets Jochen

Link to post

Could you please be more specific and give an example what are you doing on server side and what are you doing on client side?

 

From your current example I think that problem is that you trying to connect to somewhere where there is no opened socket to listen. Try to check result of sndSocket.connect() call. It should return 1 if it succeeds.

 

And here is a sample of usage for sockets:

 

Server:

 

class ServerSocket {

private:

	Socket socket = NULL;

public:

	ServerSocket(string ip,int port) {
		socket = new Socket(ip,port);
		socket.bind();
		socket.listen(10);
		if(socket.isOpened()) socket.nonblock();
	}

	~ServerSocket() {
		if(socket != NULL && socket.isOpened()) socket.close();
		delete socket;
		socket = NULL;
	}

	int isOpened() {
		return socket.isOpened();
	}

	int accept(Socket s) {
		return socket.accept(s);
	}
};

ServerSocket socket;
Socket client;

void server_loop() {

while(1) {

	if(client == NULL) client = new Socket();

	if(socket.accept(client)) {

		log.message("Client connected from %s\n",client.getHost());

		client.close();
		delete client;
		client = NULL;
	}
	wait;
}
}

/*
*/
int init() {

socket = new ServerSocket("127.0.0.1",61112);
if(socket.isOpened() == 0) {
	log.error("Could not open server socket\n");
	return;
}

client = NULL;

thread("server_loop");

engine.app.setUpdate(1);

return 1;
}

/*
*/
int shutdown() {

if(socket != NULL) {
	delete socket;
	socket = NULL;
}

if(client != NULL) {
	if(client.isOpened()) client.close();
	delete client;
	client = NULL;
}

return 1;
}

/*
*/
int update() {

return 1;
}

 

Client:

 

class ClientSocket {

private:

	Socket socket = NULL;

public:

	ClientSocket(string server_ip,int server_port) {
		socket = new Socket(server_ip,server_port);
	}

	~ClientSocket() {
		if(socket != NULL && socket.isOpened()) socket.close();
		delete socket;
		socket = NULL;
	}

	int isOpened() {
		if(socket == NULL) return 0;
		return socket.isOpened();
	}

	int connect() {
		if(socket == NULL) return 0;
		return socket.connect();
	}

	int connectBlocking(float timeout) {

		if(socket.isOpened() == 0) return 0;

		float time = clock();

		while(clock() - time < timeout) {

			if(socket.connect()) {
				return 1;
			}
		}
		return 0;
	}		
};

int do_send(string ip,int port,float connect_timeout) {

ClientSocket socket = new ClientSocket("127.0.0.1",61112);

if(socket.connectBlocking(connect_timeout) == 0) {
	log.error("Error: could not connect to server\n");
	delete socket;
	return 0;
}
log.message("Connected to server successfully\n");

delete socket;	

return 1;
}

/*
*/
int init() {

engine.app.setUpdate(1);

do_send();

return 1;
}

/*
*/
int shutdown() {

return 1;
}

/*
*/
int update() {

return 1;
}

  • Like 1
Link to post

Thanks for your fast and detail Posting.

 

The Situation is, that the ReceiveSocket is connected. This Function-Call return 1 recvSocket.accept(s);. And on my Server-Side

i already got the information that the Client is connected. But the Serverside is programmed in vb.net, but i have no probs with receiving

Stream from the Send socket in Unigine. I have only probs by getting the Stream from the receive Socket.

 

Unfortunately u only have an example for Sending in your code. It would be nice to haven an example in Receiving.

 

Thx Anet

Link to post

 

   // ...
   sndSocket = new Socket("127.0.0.1",7654);
   // ...
   sndSocket.connect();

 

What does this call return? Did you check it?

 

And do you write anything into the socket from which you are trying to read on the server side?

Could you give the sample of what are you doing on server side in vb.net?

 

Here is a sample of reading and writing data to socket:

 

Client (sends data to server):

int data_buffer[bUFFER_LENGTH];
// fill data buffer here
socket.write(data_buffer,BUFFER_LENGTH);

 

Server (receives data from client):

int data_buffer[bUFFER_LENGTH];
client.read(data_buffer,BUFFER_LENGTH);

 

You can also use any other read/write methods to read/write variables to socket.

See reference here: https://developer.unigine.com/en/docs/1.0/code/scripting/core/class.stream

  • Like 1
Link to post

Hi Anet,

 

sndSocket.connect(); Return 1. I thought that i wrote it in my first posting.

 

Thx for this Snippet

int data_buffer[bUFFER_LENGTH];
client.read(data_buffer,BUFFER_LENGTH);

 

And the Link to the Stream functions. I think this will help me by my Problem.

I will test this function on the evening.

 

But thx for your support

 

Greets Jochen

Link to post

Hi Guys,

 

now i have following Problem with my Sockets. At first i have to say that all my Sockets connect fine, and it works great with connecting.

My SendSocket can still send without Problems. But my Problem is that sometimes my update() function from unigine, make a freese in Unigine.

 

When i use socket.read(bytearray,size) it work most of the time good (only sometimes unigine get a freeze). But when i use for example readline then

i always have a freeze. And know im on the point, where i dont know why. I really hope that you can help me again

 

Socket recvSocket;
Socket sndSocket;
int recvStateConnect = 0;
int sndStateConnect = 0;
int LoopCnt = 0;
int init() {
   Logger::init();
   BuildingSystemLogger::init(); 
   sndSocket = new Socket("127.0.0.1",7654);
   recvSocket = new Socket("127.0.0.1",8654);


   sndStateConnect = sndSocket.connect();
   recvStateConnect = recvSocket.connect();

   Logger::logger (0, "netzwerk::sndStateConnect()", sndStateConnect );
   Logger::logger (0, "netzwerk::recvStateConnect()", recvStateConnect );
   return 1;
}

int shutdown() {
   if(sndSocket != NULL) {
               delete sndSocket;
               sndSocket = NULL;
   }

   if(recvSocket != NULL) {
               delete recvSocket;
               recvSocket = NULL;
   }

return 1;
}

int update() {


     if (recvStateConnect == 1) 
     {  
           if (LoopCnt == 500)
           {
                 Logger::logger (0, "netzwerk::sndStateConnect()", "check" );

                 int Succesfullread = 0;
                 int BUFFER_LENGTH = 10;
                 int data_buffer[bUFFER_LENGTH];

                 Succesfullread = recvSocket.read(data_buffer,BUFFER_LENGTH);

                 if (Succesfullread  > 0)
                 {
                 Logger::logger (0, "netzwerk::sndStateConnect()", "something read" + data_buffer[0] ); 
                 Succesfullread = 0;  
                 } 


           LoopCnt = 0;

           }
           LoopCnt = LoopCnt +1;

     }

return 1;
}

Link to post

Just an idea:

 

int Socket::nonblock()

Description
Makes the socket be non-blocking.

Return value
Positive value if the socket became non-blocking, otherwise 0.

 

Instead of Stream::readLine() you could try

 

string Socket::gets()

Description
Reads all available data from the socket.

Return value
Received string.

Link to post

hi Ulf,

 

thx for your answer.

 

This ->int Socket::nonblock()<- Setting disable a conncetion on this port.

 

And this -> string Socket::gets() <- I tried too, and i had a freeze. When i shutdown my ServerApplikation,

the freeze is gone. Its so strange that sending from unigine to vb.net is no problem, but receiving is a problem.

 

Have someone an idea?

 

Greets Jochen

Link to post

Okay now i learned following.

 

When i dont want to get a freeze, then i have to create my receiveport on this way

 

    recvSocket = new Socket("127.0.0.1",8654);

   recvSocket.bind();
   recvSocket.listen(10);
   recvSocket.nonblock();

 

and then this code in update

 

 Socket s = new Socket();

              if(recvSocket.accept(s))
               {
                                    Logger::logger (0, "netzwerk::sndStateConnect()", "hallo" );
	    }

           if(recvSocket.isOpened() == 1)
           {
              string message = "";
              message = recvSocket.gets();
              if (strlen(message) > 0) 
              {
                       Logger::logger (0, "netzwerk::sndStateConnect()", "HHHHHHHHHHHHHHHHHAAAAAAAAAAAAAAAAAAAAA" );    
                       //message = "";       
              }

           }

 

Now i get no Freeze, but i get no message also. Someone have an idea, where is my failure?

Link to post

This ->int Socket::nonblock()<- Setting disable a conncetion on this port.

Why do you think so? It should just switch socket into non-blocking mode.

Please, give an example how did you try to use it.

 

And this -> string Socket::gets() <- I tried too, and i had a freeze. When i shutdown my ServerApplikation,

the freeze is gone. Its so strange that sending from unigine to vb.net is no problem, but receiving is a problem.

This is happening because you use blocking socket and probably do not write any data into it. So receiving host is trying to read from it and blocks the thread until it gets something.

 

 

When i dont want to get a freeze, then i have to create my receiveport on this way

 

    recvSocket = new Socket("127.0.0.1",8654);

   recvSocket.bind();
   recvSocket.listen(10);
   recvSocket.nonblock();

 

and then this code in update

 

 Socket s = new Socket();

              if(recvSocket.accept(s))
               {
                                    Logger::logger (0, "netzwerk::sndStateConnect()", "hallo" );
	    }

           if(recvSocket.isOpened() == 1)
           {
              string message = "";
              message = recvSocket.gets();
              if (strlen(message) > 0) 
              {
                       Logger::logger (0, "netzwerk::sndStateConnect()", "HHHHHHHHHHHHHHHHHAAAAAAAAAAAAAAAAAAAAA" );    
                       //message = "";       
              }

           }

 

Now i get no Freeze, but i get no message also. Someone have an idea, where is my failure?

 

In this piece of code your recvSocket is acting like a server. And the only difference that eliminates freezing is this call:

recvSocket.nonblock();

 

So, if you need any more help, please, give a full example of your code. What are you trying to do on the server side (vb.net) and what are you trying to do on the client side (Unigine script).

Link to post

Why do you think so? It should just switch socket into non-blocking mode.

Please, give an example how did you try to use it.

 

Because i get no connection.

 

This is happening because you use blocking socket and probably do not write any data into it. So receiving host is trying to read from it and blocks the thread until it gets something.

In this piece of code your recvSocket is acting like a server. And the only difference that eliminates freezing is this call:

recvSocket.nonblock();

 

Yes here it is normal to get no freeze, and you are right, i have created here a Serversocket. I tried again this way with Serversockets to check if its work.

And it is how i wrote. I get no Freeze, i have connection, but i get no message.

 

Thx for the links´s, but normaly i had no problems when i programming networkapplications. I will try some other ways.

Link to post

Because i get no connection.

Could you please give an example of code that shows this?

And which operating system do you use?

There is a known bug with connecting in non-blocing mode under Windows.

 

Yes here it is normal to get no freeze, and you are right, i have created here a Serversocket. I tried again this way with Serversockets to check if its work.

And it is how i wrote. I get no Freeze, i have connection, but i get no message.

Do you write anything into this socket on the server side? Could you please provide a piece of code that does this?

Link to post

Thank you again for answer Anet

 

There is a known bug with connecting in non-blocing mode under Windows.

 

That is a good tip. I tried it under Windows 7, but someone else tried it under Linux, and in both OS we had the same problem.

 

Do you write anything into this socket on the server side?

 

Of course. I wouldn´t wonder myself, when i would not write anything in the sendsocked by my server :)

 

Could you please provide a piece of code that does this?

 

No Problem. I give you 2 Examples

 

ServerSocket on which Unigine would try to connect

 

        Dim mySendServerSocket As System.Net.Sockets.Socket
       Dim myListener As New System.Net.Sockets.TcpListener("8000")

       myListener.Start()
       If myListener.Pending Then
           mySendServerSocket = myListener.AcceptSocket
           Dim myMessage As String = "Hallo\n"
           Dim myBytes() As Byte = System.Text.Encoding.Default.GetBytes(myMessage)
           mySendServerSocket.Send(myBytes)
       End If

 

This code would run in a Thread and perhaps send every 10 seconds a message.

 

The Unigine-Code would look like so

 

Socket ClientrecvSocket ;
int recvStateConnect = 0;
init(){
   ClientrecvSocket = new Socket("127.0.0.1",8000);
   recvStateConnect = recvSocket.connect();
}
}

 

In this case i get my Freeze when i call recvStateConnect.Readline(); or recvStateConnect.Gets() in the updateFunction.

 

 

ClientSocket which would try to Connect to Unigine

 

        
Dim mySendClientSocket As System.Net.Sockets.Socket
       Dim ipep As IPEndPoint


       ipep = New IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000)
       mySendClientSocket = New System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
       mySendClientSocket.Connect(CType(ipep, EndPoint))
       If mySendClientSocket.Connected Then
           Dim myMessage As String = "Hallo\n"
           Dim myBytes() As Byte = System.Text.Encoding.Default.GetBytes(myMessage)
           mySendClientSocket.Send(myBytes)
       End If

 

unigine Code would look like this

 

Socket ServerrecvSocket;
init()
{
   ServerrecvSocket = new Socket("127.0.0.1",8000);

   ServerrecvSocket.bind();
   ServerrecvSocket.listen(10);
   ServerrecvSocket.nonblock();
}

 

 

In this case i get no Freeze when i call recvStateConnect.Readline(); or recvStateConnect.Gets(); but i get no message too.

 

If u need it, i could attach a vb-projekt in every version you want. For Info: I have no Problem with the Connection, this works

really good. The only Problem is it to receive Data from the Server. Sending Data from unigine to vb.net is also no Problem its works fine.

 

Greets Jochen

Link to post

Ok, I've reproduced your problem. If blocking mode is used client hangs until it receives next portion of data.

And non-blocking mode seems to be broken.

 

For which purposes are you going to use these sockets?

What are you going to send to client in a loop?

 

We internally use these sockets only to send some statistics data from client to server once. So we use them only in the following way:

1. Create socket

2. Connect to server

3. Write data into socket

4. Close socket

 

All other networking is done using network module: https://developer.unigine.com/en/docs/1.0/code/scripting/network/

Link to post

Your first thought with the dataformat i had too. But sometimes i got the String back like Hallo or i filled the bytearray.

But it works more like random :). so i can not say in this situation i will get a string/stream.

 

I think that somewhere in the streamnig is the problem. Perhaps a proberty which can give you information about the content in the

Socket would be nice.

 

In vb.net i have a proberty called

 

mySendServerSocket.Available

 

this gives me a integer back, about the contentlength.

Link to post

Ok, I've reproduced your problem. If blocking mode is used client hangs until it receives next portion of data.

And non-blocking mode seems to be broken.

 

For which purposes are you going to use these sockets?

What are you going to send to client in a loop?

 

We internally use these sockets only to send some statistics data from client to server once. So we use them only in the following way:

1. Create socket

2. Connect to server

3. Write data into socket

4. Close socket

 

All other networking is done using network module.

 

 

Okay that was the Info what i needed. I had the presumption that you only use it for sending and not primary for receiving.

 

My vb.net is a kind of interface between a Database and Unigine, so there will be always a communication between the Server and Unigine.

And will send some defined Telegramms between both of them. When there is a problem/bug with the receiving then i also could use this

network module.

 

 

So the Conclusion is that i can not use the sockets to receive Data from vb.net or?

 

Greets Jochen

Link to post

So the Conclusion is that i can not use the sockets to receive Data from vb.net or?

 

Conclusion should be to fix non-blocking data reception as working low-level socket communication is a must (especially to be able to bridge different OS/Programming Languages). It would be quite strange if non-blocking mode is not possible under Windows.

Link to post

Hi Again,

 

now i have a solution for the problem, its really not fine, but it work.

 

After I send a message over vb.net i have to close the Socket on the ServerSide. Then its possible for Unigine to get the message.

It sounds funny, but it isnt.

       If Not mySendSocket Is Nothing AndAlso mySendSocket.Connected Then
           If mySendSocket.Available > 0 Then
               Dim bytes() As Byte
               Dim readable As Integer = mySendSocket.Available
               ReDim bytes(readable - 1)



               Dim myinteger As Integer = 0
               myinteger = mySendSocket.Receive(bytes)
               System.Threading.Thread.Sleep(500)
               mySendSocket.Send(bytes)
               mySendSocket.Disconnect(False)
               mySendSocket.Dispose()
               mySendSocket = Nothing
           End If
       End If

 

and here my Code in Unigine. I haev to add here something, so that i can work with my second Socket.

 

Socket recvSocket;
Socket sndSocket;
Socket sndSocket2;
int recvStateConnect = 0;
int sndStateConnect = 0;
int LoopCnt = 0;

int MessageWasSend = 0;
int init() {
   Logger::init();
   BuildingSystemLogger::init(); 
   sndSocket = new Socket("127.0.0.1",7654);
   recvSocket = new Socket("127.0.0.1",8888);
   Logger::logger (0, "netzwerk::sndStateConnect()", "test" );


   sndStateConnect = sndSocket.connect();
   sndSocket.puts("test");
   engine.app.setUpdate ( 1 );
   return 1;
}

int shutdown() {
   if(sndSocket != NULL) {
               delete sndSocket;
               sndSocket = NULL;
   }

   if(recvSocket != NULL) {
               delete recvSocket;
               recvSocket = NULL;
   }

return 1;
}

int update() {

           if(sndSocket.isOpened() == 1)
           {
              string message = "";
              message = sndSocket.gets();
              if (strlen(message) > 0) 
              {
                       Logger::logger (0, "netzwerk::sndStateConnectmessage()", message );    
                       message = "";      
                       MessageWasSend = 1;
                       sndSocket.close();
                       delete sndSocket;
                       sndSocket = NULL;
                       MessageWasSend = 1;
              }
           }

           if(MessageWasSend == 1)
           {
             //Open a New Socket just for test
             sndSocket2 = new Socket("127.0.0.1",7654);
             sndStateConnect = sndSocket2.connect();
             MessageWasSend = 0;  
             Logger::logger (0, "netzwerk::sndSocket2() neue verbindung", sndStateConnect );                    
           }

return 1;
}

 

 

With this Code i get no freeze, and i can continue with unigine handling. But so or so, i can not reopen my first Socket again.

When I try this, Unigine gets a freeze. I think that it still have an handle on the first socket after I set it on NULL.

 

Greets Jochen

Link to post

My vb.net is a kind of interface between a Database and Unigine, so there will be always a communication between the Server and Unigine.

And will send some defined Telegramms between both of them. When there is a problem/bug with the receiving then i also could use this

network module.

 

So the Conclusion is that i can not use the sockets to receive Data from vb.net or?

 

What are these telegramms? Do they represent some game state?

If so, then it is not recommended to use Unigine sockets. They are not intended to be used for game networking. Use network plugin instead (It uses RakNet for low-level network communication http://www.jenkinssoftware.com/).

Another way is to use any other 3d party network library or develop your own network code.

 

But if you want to send several bytes of data once, then you can use Unigine sockets.

Link to post

Hello Anet

 

We (try) to use the socket connection for simply data sharing between our database which is connected to the vb.net application and the unigine instance which is running as server in our server infrastructure. While the unigine instance also deals with client connections with help of the raknet library (network.*) I do not want to use raknet against the vb.net application. While performance of the client connections are essential, the performance and delay to the vb.net application is not. Too it´s overkilled to link against it in the vb.net application. Too the raknet instance only listens on the public interface, while the socket should only listen on the private interface. There would be a big security problem while the instance of raknet can access the database from the outside. In this case I can’t secure it against attacks without some dirty hacks.

 

About your question, a telegram is a specified message that is send to the socket with minimal data (action to perform and an internal id). This data too needs no synchronization at all. The vb.net application is only an interface for checking and updating database fields. Return values only are true or false and in some cases a primary key.

 

We tested the last night some use cases with linux and windows as platform. When sockets are working well in windows, they are totally broken in linux.

It seems that the socket class is not well maintained. Is there a plan to fix these problems with this class? When not I try to load the libboost sockets functions as a plugin into unigine which can handle network for multiple platforms.

 

 

Greets

Manuel

Link to post

After I send a message over vb.net i have to close the Socket on the ServerSide. Then its possible for Unigine to get the message.

 

Just a guess based on working data reception in case of server socket closure: Normally close() calls internally flush(), so I would try 2 possible fixed on your vb.net server code:

 

1) mySendSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1) on server socket creation

 

If this does not work, than

 

2) mySendSocket.Flush() on server socket after each server mySendSocket.Send()

Link to post

Hi Ulf,

 

big Thanks to this two Codesnippets. I will try it in the evening how it works, and will give you a feedback.

For me this Code looks logic, i havent known this :).

 

 

Thanks again.

 

Greets jochen

Link to post

We tested the last night some use cases with linux and windows as platform. When sockets are working well in windows, they are totally broken in linux.

It seems that the socket class is not well maintained. Is there a plan to fix these problems with this class? When not I try to load the libboost sockets functions as a plugin into unigine which can handle network for multiple platforms.

 

Hello Manuel,

We are not planning to support Unigine sockets. So it will be better to try boost sockets.

Link to post

Hello Manuel,

We are not planning to support Unigine sockets. So it will be better to try boost sockets.

 

Hello anet

 

Thanks for the for information.

Implementation with the boost sockets was successful.

Sockets now working in a sweet async mode. :)

 

 

greets

Manuel

Link to post