我这两天以后就受到了这个代码的困扰。事实上,我正在开发一个具有服务器端和客户端的应用程序。服务器每秒接收来自客户端的请求,通过联系数据库处理请求,然后将结果发送回客户端。
我这样做,如果客户端在服务器之前启动,它将继续尝试连接到给定端口和给定主机上的服务器。
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循环
- 客户端。在另一个线程中,每次尝试联系服务器以建立连接
- 再次在另一个线程中,客户端向服务器发送请求
- 服务器是另一个线程请求来自数据库的信息并发送回客户端。
非常感谢你的帮助
答案 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对象。多数民众赞成。