13 Replies Latest reply on Aug 8, 2007 3:21 AM by ron_sigal

    Simple Socket Server (TEXT)?

    hurzeler

      I need help!
      How do I go about to create a simple text socket server that I can communicate with for example via telnet? I use JBoss4.0.5GA and JBoss4.2.0GA.

      On JBoss4.0.5GA the problem I am facing is that the un/marshaller does not get used. On JBoss4.2.0GA I get

      --- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
      
      ObjectName: com.test:service=Connector,transport=socket
      
       State: FAILED
      
      Reason: org.jboss.remoting.InvalidConfigurationException: The invoker for locator (InvokerLocator [socket://localhost:8084/?dataType=invocation&enableTcpNoDelay=true&marshaller=com.test.socket.V75SocketServer.TextMarshaller&socketTimeout=600000&unmarshaller=com.test.socket.V75SocketServer.TextUnMarshaller]) is already in use by another Connector. Either change the locator or add new handlers to existing Connector.
      


      I can see that a socket server is defined in server/default/conf/jboss-service.xml but I would think it should be possible to stick another socket server on a different port.

      <server>
       <!-- ==================================================================== -->
       <!-- Invokers to the JMX node -->
       <!-- ==================================================================== -->
       <mbean code="org.jboss.remoting.transport.Connector"
       name="com.test:service=Connector,transport=socket"
       display-name="Socket transport Connector">
       <attribute name="Configuration">
       <config>
       <invoker transport="socket">
       <attribute name="dataType" isParam="true">invocation</attribute>
       <attribute name="marshaller" isParam="true">com.test.socket.V75SocketServer.TextMarshaller</attribute>
       <attribute name="unmarshaller" isParam="true">com.test.socket.V75SocketServer.TextUnMarshaller</attribute>
       <attribute name="serverSocketClass">com.test.socket.V75SocketServer.SimpleInputStreamWrapper</attribute>
       <attribute name="socketTimeout" isParam="true">600000</attribute>
       <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
       <attribute name="serverBindPort">8084</attribute>
       <attribute name="enableTcpNoDelay" isParam="true">true</attribute>
       </invoker>
       <handlers>
       <handler subsystem="V75">com.test.socket.V75SocketServer.Handler</handler>
       </handlers>
       </config>
       </attribute>
       </mbean>
      
      </server>


      Thanks for your help.

        • 1. Re: Simple Socket Server (TEXT)?
          ron_sigal

          The error message means that another Connector with exactly the same InvokerLocator,


          socket://localhost:8084/?dataType=invocation&enableTcpNoDelay=true&marshaller=com.test.socket.V75SocketServer.TextMarshaller&socketTimeout=600000&unmarshaller=com.test.socket.V75SocketServer.TextUnMarshaller


          has already been created. Are you sure you don't have two MBeans, in some *-service.xml files, with the same attributes? If you really changed the "serverBindPort" attribute, you should be able to create a second Connector.



          • 2. Re: Simple Socket Server (TEXT)?
            hurzeler

            Yes there is actually a second socket in jboss-4.2.0.GA/server/default/conf/jboss-service.xml but as far as I can see it is on port 4446. Mine should go on port 8084. The name of the mbean is also different??? So therefore I can't see what is wrong. Further this part worked ok on jboss4.0.5GA but the un/marshalling did not. I guess this is because of the different remoting version.

            Is this a bug???


            This is the socket that conflicts in the default jboss-4.2.0.GA/server/default/conf/jboss-service.xml:

             <!-- The Connector is the core component of the remoting server service. -->
             <!-- It binds the remoting invoker (transport protocol, callback configuration, -->
             <!-- data marshalling, etc.) with the invocation handlers. -->
             <mbean code="org.jboss.remoting.transport.Connector"
             name="jboss.remoting:service=Connector,transport=socket"
             display-name="Socket transport Connector">
            
             <!-- Can either just specify the InvokerLocator attribute and not the invoker element in the -->
             <!-- Configuration attribute, or do the full invoker configuration in the in invoker element -->
             <!-- of the Configuration attribute. -->
            
             <!-- Remember that if you do use more than one param on the uri, will have to include as a CDATA, -->
             <!-- otherwise, parser will complain. -->
             <!-- <attribute name="InvokerLocator"><![CDATA[socket://${jboss.bind.address}:4446/?datatype=invocation]]></attribute> -->
            
             <attribute name="Configuration">
             <!-- Using the following <invoker> element instead of the InvokerLocator above because specific attributes needed. -->
             <!-- If wanted to use any of the parameters below, can just add them as parameters to the url above if wanted use the InvokerLocator attribute. -->
             <config>
             <!-- Other than transport type and handler, none of these configurations are required (will just use defaults). -->
             <invoker transport="socket">
             <attribute name="dataType" isParam="true">invocation</attribute>
             <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationMarshaller</attribute>
             <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationUnMarshaller</attribute>
             <!-- This will be port on which the marshall loader port runs on. -->
             <!-- <attribute name="loaderport" isParam="true">4447</attribute> -->
             <!-- The following are specific to socket invoker -->
             <!-- <attribute name="numAcceptThreads">1</attribute>-->
             <!-- <attribute name="maxPoolSize">303</attribute>-->
             <!-- <attribute name="clientMaxPoolSize" isParam="true">304</attribute>-->
             <attribute name="socketTimeout" isParam="true">600000</attribute>
             <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
             <attribute name="serverBindPort">4446</attribute>
             <!-- <attribute name="clientConnectAddress">216.23.33.2</attribute> -->
             <!-- <attribute name="clientConnectPort">7777</attribute> -->
             <attribute name="enableTcpNoDelay" isParam="true">true</attribute>
             <!-- <attribute name="backlog">200</attribute>-->
             <!-- The following is for callback configuration and is independant of invoker type -->
             <!-- <attribute name="callbackMemCeiling">30</attribute>-->
             <!-- indicates callback store by fully qualified class name -->
             <!-- <attribute name="callbackStore">org.jboss.remoting.CallbackStore</attribute>-->
             <!-- indicates callback store by object name -->
             <!-- <attribute name="callbackStore">jboss.remoting:service=CallbackStore,type=Serializable</attribute> -->
             <!-- config params for callback store. if were declaring callback store via object name, -->
             <!-- could have specified these config params there. -->
             <!-- StoreFilePath indicates to which directory to write the callback objects. -->
             <!-- The default value is the property value of 'jboss.server.data.dir' and if this is not set, -->
             <!-- then will be 'data'. Will then append 'remoting' and the callback client's session id. -->
             <!-- An example would be 'data\remoting\5c4o05l-9jijyx-e5b6xyph-1-e5b6xyph-2'. -->
             <!-- <attribute name="StoreFilePath">callback</attribute>-->
             <!-- StoreFileSuffix indicates the file suffix to use for the callback objects written to disk. -->
             <!-- The default value for file suffix is 'ser'. -->
             <!-- <attribute name="StoreFileSuffix">cst</attribute>-->
             </invoker>
            
             <!-- At least one handler is required by the connector. If have more than one, must decalre -->
             <!-- different subsystem values. Otherwise, all invocations will be routed to the only one -->
             <!-- that is declared. -->
             <handlers>
             <!-- can also specify handler by fully qualified classname -->
             <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>
             </handlers>
             </config>
             </attribute>
             <depends>jboss.remoting:service=NetworkRegistry</depends>
             </mbean>
            


            • 3. Re: Simple Socket Server (TEXT)?
              ron_sigal

              Conflicting MBean names wouldn't cause this particular error message. The conflict lies in the InvokerLocator. The message is saying that, one way or another, a Connector with exactly the same InvokerLocator has already been created. One thing to try would be to start up the Application Server, point your web browser to the jmx console (http://localhost:8080/jmx-console/), and see if you an MBean named "com.test:service=Connector,transport=socket". If so, it must be defined in two places.

              • 4. Re: Simple Socket Server (TEXT)?
                hurzeler

                Ok yes I am an idiot. I had an old jar file in the deploy directory.

                Now the sar gets deployed ok and answers on port 8084. The problem I have now is that remoting complains about the version of the data:

                18:18:51,734 ERROR [ServerThread] Worker thread initialization failure
                java.io.IOException: Can not read data for version 116. Supported versions: 1,2,22
                 at org.jboss.remoting.transport.socket.ServerThread.versionedRead(ServerThread.java:660)
                 at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:530)
                 at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:369)
                 at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:165)


                I am trying to send simple text to the socket via telnet. On the server side I do not want any fancy deserialization happening. I just want to get the InputStream (SimpleInputStreamWrapper getInputStream() returns a simple InputStream) and read the data of that InputStream (TextUnMarshaller read(InputStream is, Map map) returns a String).

                May be I misunderstand the concept but I definitely do not understand the above error message.
                Thanks for your help.


                • 5. Re: Simple Socket Server (TEXT)?
                  ron_sigal

                  Since version 2.0.0, Remoting has preceded each message on the wire with a version byte. The valid version bytes, currently, are 1, 2, and 22. If you are using the same version of Remoting on the client and server, there shouldn't be a problem.

                  But, you said you are using telnet as the client, which, of course, doesn't send a version byte. If you are using Remoting 2.0.0+, the default behavior is to treat the first available byte on the stream as a version byte, in this case a 't'.

                  You want to turn off versioning. If you set the system property "jboss.remoting.pre_2_0_compatible" to true on the server side, Remoting will think it is talking to a pre 2.0.0 version of Remoting and will not expect a version byte.

                  • 6. Re: Simple Socket Server (TEXT)?
                    hurzeler

                    Thanks for that. Do I turn off the versioning programatically in for example my SimpleInputStreamWrapper or do I do this in the jboss-service.xml file of my socket server or may be as -D argument to jboss. However the last option is probably not a good idea as it would turn off the versioning for all other remoting services as well. Please advice. Thanks

                    • 7. Re: Simple Socket Server (TEXT)?
                      ron_sigal

                      Whether you set the system property programatically or on the command line, it will be set for all Remoting clients and servers in the JVM. Currently, this is the only option. I've created a JIRA issue JBREM-764 (http://jira.jboss.com/jira/browse/JBREM-764) to make the wire format configurable per client or server.

                      In the meantime, one workaround would be to fiddle with the telnet client. The Apache Jakarta Commons Net project, for example, has support for telnet, and the synopsis at http://jakarta.apache.org/commons/net/ says


                      Our philosophy is to make the global functionality of a protocol accessible (e.g., TFTP send file and receive file) when possible, but also provide access to the fundamental protocols where applicable so that the programmer may construct his own custom implementations (e.g, the TFTP packet classes and the TFTP packet send and receive methods are exposed).


                      By the way, not all services in the Application Server use Remoting. EJB3, JBossMessaging, and JBoss Web Services (but just for SOAP clients) are services that do use Remoting. If you don't use those, then you should be OK. Moreover, while I suspect that JBossMessaging wouldn't work with an older wire format, I'm not sure that the other services would notice.

                      • 8. Re: Simple Socket Server (TEXT)?
                        hurzeler

                        Thanks again for all the help. I found that setting the flag -Djboss.remoting.pre_2_0_compatible=true on the server works great for the socket server but one has to set this flag as well on remote clients if they want to do a JNDI lookup on the InitialContext.

                        One other question that cam up was how and where do we close the socket ofter the socket client has been served and sent a result back?

                        • 9. Re: Simple Socket Server (TEXT)?
                          ron_sigal

                           

                          One other question that cam up was how and where do we close the socket ofter the socket client has been served and sent a result back?


                          I take it you are asking about closing the socket on the server side? You really shouldn't have to worry about it.

                          The default socket transport behavior is for each socket to be held by a worker thread, which, after processing an invocation, sits in a read() waiting for the next invocation. The default timeout is 60000 ms, after which the socket will be closed. You can change the timeout by adding a "timeout" attribute:

                           <invoker transport="socket">
                           <attribute name="timeout">5000</attribute>
                          


                          By the way, "socketTimeout" is obsolete - it really should be removed from jboss-service.xml.

                          • 10. Re: Simple Socket Server (TEXT)?
                            cazuza


                            Appologies in advance if the questions are too naive, but I'm just starting with Jboss and have a head full of doubts.

                            I have try to implement a socket server using this approach and have hit a wall.
                            the timeout attribute works but doesn't close the socket instead it sends error messages to the console.

                            16:05:52,492 ERROR [STDERR] java.net.SocketTimeoutException: Read timed out
                            16:05:52,492 ERROR [STDERR] at java.net.SocketInputStream.socketRead0(Native Method)
                            16:05:52,492 ERROR [STDERR] at java.net.SocketInputStream.read(SocketInputStream.java:129)
                            16:05:52,492 ERROR [STDERR] at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
                            16:05:52,493 ERROR [STDERR] at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
                            16:05:52,493 ERROR [STDERR] at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
                            16:05:52,493 ERROR [STDERR] at java.io.InputStreamReader.read(InputStreamReader.java:167)
                            16:05:52,493 ERROR [STDERR] at java.io.BufferedReader.fill(BufferedReader.java:136)
                            16:05:52,493 ERROR [STDERR] at java.io.BufferedReader.readLine(BufferedReader.java:299)
                            16:05:52,493 ERROR [STDERR] at java.io.BufferedReader.readLine(BufferedReader.java:362)
                            16:05:52,493 ERROR [STDERR] at com.thetote.dbi.socket.TextUnMarshaller.read(TextUnMarshaller.java:53)
                            16:05:52,493 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.versionedRead(ServerThread.java:652)
                            16:05:52,493 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:530)
                            16:05:52,493 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:383)
                            16:05:52,493 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:165)
                            16:05:57,492 ERROR [STDERR] java.net.SocketTimeoutException: Read timed out
                            16:05:57,493 ERROR [STDERR] at java.net.SocketInputStream.socketRead0(Native Method)
                            16:05:57,493 ERROR [STDERR] at java.net.SocketInputStream.read(SocketInputStream.java:129)
                            16:05:57,493 ERROR [STDERR] at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
                            16:05:57,493 ERROR [STDERR] at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
                            16:05:57,493 ERROR [STDERR] at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
                            16:05:57,493 ERROR [STDERR] at java.io.InputStreamReader.read(InputStreamReader.java:167)
                            16:05:57,493 ERROR [STDERR] at java.io.BufferedReader.fill(BufferedReader.java:136)
                            16:05:57,494 ERROR [STDERR] at java.io.BufferedReader.readLine(BufferedReader.java:299)
                            16:05:57,494 ERROR [STDERR] at java.io.BufferedReader.readLine(BufferedReader.java:362)
                            16:05:57,494 ERROR [STDERR] at com.thetote.dbi.socket.TextUnMarshaller.read(TextUnMarshaller.java:53)
                            16:05:57,494 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.versionedRead(ServerThread.java:652)
                            16:05:57,494 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:530)
                            16:05:57,494 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:383)
                            16:05:57,494 ERROR [STDERR] at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:165)

                            unless the client closes the connection itself it seems that the server will timeout and write error messages to STDERR. I don't want to rely on the client to close the connection, is it possible to close the socket connection after sending the response?

                            the other question is How do I send multiple messages back to the client. At the moment on my invoke method I receive the request, parse it and return a string, what do I have to do to send another string without concatenating on the previous string?

                            this is my config file


                            <!-- ==================================================================== -->
                            <!-- Invokers to the JMX node -->
                            <!-- ==================================================================== -->
                            <mbean code="org.jboss.remoting.transport.Connector"
                            name="com.xxxx:service=Connector,transport=socket"
                            display-name="RacingDB Socket transport Connector">



                            5000
                            text
                            com.xxxx.dbi.socket.TextMarshaller
                            com.xxxx.dbi.socket.TextUnMarshaller
                            com.xxxx.dbi.socket.SimpleInputStreamWrapper
                            ${jboss.bind.address}
                            6193
                            true


                            com.xxxx.dbi.socket.Handler





                            • 11. Re: Simple Socket Server (TEXT)?
                              cazuza

                              sorry the config file is here


                              <!-- ==================================================================== -->
                              <!-- Invokers to the JMX node -->
                              <!-- ==================================================================== -->
                              <mbean code="org.jboss.remoting.transport.Connector"
                              name="com.xxxx:service=Connector,transport=socket"
                              display-name="RacingDB Socket transport Connector">



                              5000
                              text
                              com.xxxx.dbi.socket.TextMarshaller
                              com.xxxx.dbi.socket.TextUnMarshaller
                              com.xxxx.dbi.socket.SimpleInputStreamWrapper
                              ${jboss.bind.address}
                              6193
                              true


                              com.xxxx.dbi.socket.Handler





                              • 12. Re: Simple Socket Server (TEXT)?
                                cazuza

                                 

                                "cazuza" wrote:
                                sorry the config file is here



                                <server>
                                <!-- ==================================================================== -->
                                 <!-- Invokers to the JMX node -->
                                 <!-- ==================================================================== -->
                                 <mbean code="org.jboss.remoting.transport.Connector"
                                 name="com.xxxx:service=Connector,transport=socket"
                                 display-name="RacingDB Socket transport Connector">
                                 <attribute name="Configuration">
                                 <config>
                                 <invoker transport="socket">
                                 <attribute name="timeout">5000</attribute>
                                 <attribute name="dataType" isParam="true">text</attribute>
                                 <attribute name="marshaller" isParam="true">com.xxxx.dbi.socket.TextMarshaller</attribute>
                                 <attribute name="unmarshaller" isParam="true">com.xxxx.dbi.socket.TextUnMarshaller</attribute>
                                 <attribute name="serverSocketClass">com.xxxx.dbi.socket.SimpleInputStreamWrapper</attribute>
                                 <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
                                 <attribute name="serverBindPort">6193</attribute>
                                 <attribute name="enableTcpNoDelay" isParam="true">true</attribute>
                                 </invoker>
                                 <handlers>
                                 <handler subsystem="RDBIS">com.xxxx.dbi.socket.Handler</handler>
                                 </handlers>
                                 </config>
                                 </attribute>
                                 </mbean>
                                
                                </server>


                                • 13. Re: Simple Socket Server (TEXT)?
                                  ron_sigal

                                   

                                  Appologies in advance if the questions are too naive, but I'm just starting with Jboss and have a head full of doubts.


                                  No apologies necessary. We all start somewhere.

                                  I have try to implement a socket server using this approach and have hit a wall.
                                  the timeout attribute works but doesn't close the socket instead it sends error messages to the console.


                                  Actually, ServerThread should catch the SocketTimeoutException, close the socket, and return itself to the thread pool. See org.jboss.remoting.transport.socket.ServerThread.dorun().



                                  How do I send multiple messages back to the client.


                                  There is a callback mechanism in which the server may asynchronously send callbacks to a listener (org.jboss.remoting.callback.InvokerCallbackHandler) on the client side. See Section "5.6. Callbacks" in the Remoting Guide (http://labs.jboss.com/jbossremoting/docs/guide/).