MultiClient / Server。处理通讯

时间:2012-07-24 05:37:57

标签: java multithreading sockets client-server

我这两天以后就受到了这个代码的困扰。事实上,我正在开发一个具有服务器端和客户端的应用程序。服务器每秒接收来自客户端的请求,通过联系数据库处理请求,然后将结果发送回客户端。 我这样做,如果客户端在服务器之前启动,它将继续尝试连接到给定端口和给定主机上的服务器。
1.这是服务器端:

try
    {   
        Client client = new Client(jTable1,jLabel3);
        Thread t = new Thread(client);
        t.start();

    }catch(IOException e){}

Class Client.java

public class Client implements Runnable{

private int svrPort = 0;
ServerSocket serverConnect = null;
static  Socket clientSocket = null;
static  ClientConnectThread t[] = new ClientConnectThread[1000];
JTable jtable;
JLabel jlabel;

public Client(JTable table, JLabel label) throws IOException {

    this.svrPort = 9450;
    this.jtable = table;
    this.jlabel = label;

}

public void run(){
    try{
        serverConnect = new ServerSocket(this.svrPort);

    }catch(IOException e){}
    while(true){
        try{
            clientSocket = serverConnect.accept ();
            for(int i=0; i<=1000; i++){ //I can accept up to 1000 clients
        if(t[i]==null)
        {
            (t[i] = new ClientThread(client, t, jtable, jlabel)).start();
                        System.out.println ("Etat12. Apres bloc try");
            break;
        }
    }
        }catch(IOException e){}
    }
}

}

Class ClientThread.java

public ClientThread(Socket socket, ClientThread t[], JTable table, JLabel label){

    this._socket = socket;
    this.jTable = table;
    this.jlabel = label;
    this.totalConnected = 0;       
    this.t = t;
}

public void run(){

    int index = 0;
    try{
        this._output = new PrintWriter(this._socket.getOutputStream ());
        this._input = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));

        while((clientMsg = this._input.readLine ()) != null){
            if(clientMsg.equals ("@CONNECT")){ // If it is the first time the user is signig in, fill the table

                jTable.setValueAt (this._socket.getInetAddress (), index, 0);
                jTable.setValueAt (new Date(), index, 1);
                jTable.setValueAt (new Date(), index, 2);
                totalConnected++;
                jlabel.setText ("");
                jlabel.setText (totalConnected+"");

            }else if(Integer.parseInt (clientMsg) == 1){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (1).size () == 0){
                    }
                    _output.println (this.getData.getDataByPeriod (1));
                }else{System.out.println("You are not connected to the database server");}

            }else if(Integer.parseInt (clientMsg) == 2){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByPeriod (2).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByPeriod (2));
                }else{System.out.println("You are not connected to the database server");}


            }else if(Integer.parseInt (clientMsg) == 3){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (3).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByType (30));
                }else{System.out.println("You are not connected to the database server");}


            }else if(Integer.parseInt (clientMsg) == 4){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (4).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByType (60));
                }else{System.out.println("You are not connected to the database server");}


            }else{

            }
        }
        this._input.close ();
        this._output.close ();
    }catch(IOException e){}

}

这两个类使我的服务器运行。 Client.java类启动并等待接受连接。当客户端连接时,创建clientThread的实例并将其关联到客户端。 直到这里,每件事似乎都运作良好。

客户端

public class ServerConnect implements Runnable{

public static Socket clientSocket = null;
public static PrintWriter out = null;
public static BufferedReader in = null;
public static int port=9450;
public static String host = "127.0.0.1";
public static JLabel myLabel;
public static JButton button;
public static ResourceMap resourceMap;
private static String serverMsg = "";

public ServerConnect(JLabel jLabel, JButton b)
{
    jLabel.setText ("Trying to contact the server");
    myLabel = jLabel;
    button = b;
    port = Integer.parseInt("9450");
    host = "127.0.0.1";

        try{
            clientSocket = new Socket(host, port);
            }catch(IOException e){e.printStackTrace ();}

}

public void run()
{
    while(true){
        while(!this.connect ())
        {myLabel.setText ("You are not connected to the server : "+host);
         button.setEnabled (false);
            try{
                clientSocket = new Socket(host, port);
            }catch(IOException e){}
        }

        myLabel.setText ("You are connected to the server : "+host);
        button.setEnabled (true);
        try{
           out = new PrintWriter(clientSocket.getOutputStream(), true);
           out.println("@CONNECT");

           in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
           while((serverMsg = in.readLine ()) != null){
                System.out.println ("<=> :"+serverMsg);
           }
        }
        catch(IOException e){e.printStackTrace ();}
    }
}
private boolean connect()
{
    try{
        clientSocket = new Socket(host, port);
        return true;
    }catch(IOException e){}
    return false;
}}

我的问题是,当双方正在启动时,客户端发送@CONNECT的唯一内容是,服务器接收它并且所有都停在这里。如果客户端再次发送请求,则服务器不回答 我想有人一步一步地告诉我如何设置这个应用程序
- 服务器端。接受线程中的连接与WHILE循环
- 客户端。在另一个线程中,每次尝试联系服务器以建立连接
- 再次在另一个线程中,客户端向服务器发送请求
- 服务器是另一个线程请求来自数据库的信息并发送回客户端。

非常感谢你的帮助

2 个答案:

答案 0 :(得分:1)

哦,将一切都放在带有PrintWriter等的低级插槽上是一个坏主意。 我过去遇到了几个编码和多线程错误。所以我的(当然有点慢,但易于使用)解决方案是:泽西&amp;篦条筛。

最大的好处是:您可以非常轻松地修改和扩展传输对象,而无需修改传输代码(低级套接字写入)

界面......

public interface I_ServiceCommons {
        public static final String  MEDIATYPE           = "text/xml";
        public static final String  MEDIATYPE_ENCODING  = I_ServiceCommons.MEDIATYPE + "; charset=utf-8";
        public static final String SERIVCENAME = "/FUNNY_SERVICE_V001";
    }

服务器端代码

@Path(I_ServiceCommons.SERIVCENAME)
public class YourService {

    @POST
    @Produces(I_ServiceCommons.MEDIATYPE)
    @Consumes(I_ServiceCommons.MEDIATYPE)
    public ResultObject request(final RequestObject yourRequest) {
        //process here your request in Server
    }
}

您的客户......

public class abstract YourAbstractClient{
        protected Logger                            log             = Logger.getLogger(this.getClass());
        protected final String                      serviceUrl;
        private final WebResource                   resource;

        public YourAbstractClient(final String url) {
            this.serviceUrl = url + getService();
            this.resource = Client.create().resource(this.serviceUrl);
        }

        public abstract String getService();

        protected <RES, REQ> RES post(final Class<RES> resultClazz, final REQ req) {
            final Builder builder = this.resource.type(I_ServiceCommons.MEDIATYPE).accept(I_ServiceCommons.MEDIATYPE);
            try {
                final RES result = builder.post(resultClazz, req);
                return result;
            } catch (final Exception e) {
                throw new RuntimeException("Error posting data to [" + this.serviceUrl + "]: " + e.getMessage(), e);
            }
        }

    }

您的ServiceClient ......

public class Service extends YourAbstractClient {

    public Service(final String url) {
        super(url);
    }

    public MyResult getResult(final MyRequest req) {
        return super.post(MyResult.class, req);
    }

    @Override
    public String getService() {
        return I_ServiceCommons.SERIVCENAME;
    }
}

您的TransferObjects

@XmlRootElement
public class MyRequest implements Serializable {
    public void setRequestType(final int p_AequestType) {
        this.requestType = p_AequestType;
    }

    public int getRequestType() {
        return this.requestType;
    }
}

结束......

String url = "http://127.0.0.1";
GrizzlyServerFactory.create(url) //starts the server
MyRequest res = new MyRequest();
MyResult result = new Service(url).getResult(req); // Corrected

答案 1 :(得分:0)

它很安静 - 但是底层技术很复杂。 ;) 我按照相反的顺序(我的答案@ https://stackoverflow.com/a/11625335/1268954)解释它。

在主代码中,您使用GrizzlyServerFactory.create(url)启动Grizzlyserver,它监听&#34; 127.0.0.1&#34;。

当服务器启动时,它会搜索带有注释@Path的类...并找到&#34; YourService&#34;。

所以Grizzly会#34;注册&#34; (或类似的东西)ServiceClass&#34; YourService&#34;在网址&#34; http://127.0.0.1/FUNNY_SERVICE_V001&#34; (见I_ServiceCommons)。

嗯..我们又在主码中了。我们创建一个MyRequest对象并创建具体服务的实例&#34; Service&#34;。一个更好的名称应该是&#34; ServiceClient&#34;,因为它是客户端的代码。 &#34;服务&#34;使用url(&#34; http://127.0.0.1&#34;)创建,并在YourAbstractClient中进入公共构造函数代码(适用于所有客户端)并创建service-url&#34; http://127.0.0.1/FUNNY_SERVICE_V001& #34; 。在YourAbstractClient内部,将创建一个客户端对象(用于连接/编码处理等)。 当我们想要访问服务器时,我们只需要将MyRequest对象放入&#34; getResult&#34; &#34;服务&#34;的方法。 YourAbstractClient中的客户端将MyRequest对象转换为XML Reresentation(注意@XMLRootElement Annotation,无参数构造函数并在其中设置/获取方法)对服务器执行HTTP POST,从而重新创建MyRequest对象。

所以在服务器端再次...... 因此,当客户端连接到&#34; http://127.0.0.1/FUNNY_SERVICE_V001&#34;以正确的方式,服务器创建YourService的实例(需要无参数构造函数)并读取xml,创建transferobject MyRequest并将其放入方法public ResultObject request(final RequestObject yourRequest),因为它使用@POST Annotation注释(在客户端中)我们做HTTP-POST)。您可以处理MyReqeust对象,必须返回一个MyResult对象,它将转换为xml,由客户端发送,接收并重新创建到MyResult对象。多数民众赞成。