步步测试完善Java中Socket通信图解法(三)

来源:互联网 发布:国泰安数据库账号 编辑:程序博客网 时间:2024/05/17 17:16

步步测试完善Java中Socket通信图解法(一)
http://blog.csdn.net/llhhyy1989/article/details/8471725

 

步步测试完善Java中Socket通信图解法(二)
http://blog.csdn.net/llhhyy1989/article/details/8479626


步步测试完善Java中Socket通信图解法(三)
http://blog.csdn.net/llhhyy1989/article/details/8503955

---------------------------------------------------------------------------------------------------------------------------------------

http://blog.csdn.net/llhhyy1989/article/details/8503955

步步测试完善Java中Socket通信图解法(三)

分类: j2SE 2013-01-15 09:37 582人阅读 评论(3)收藏举报
javasocket

目录


简介

Java中Socket通信简介

单线程一对一服务器1——>1客户端

单线程一对一服务器1<——>1客户端

多线程一对多服务器1<——>N客户端【非聊天室的服务器通过用户输入发送数据】

多线程一对多服务器1<——>N客户端【聊天室】

多线程最终服务器和客户端集成一体【swing程序】



【多线程】一对多服务器1<——>N客户端(非聊天室的服务器通过用户输入发送数据)
对,解决方案,就是发送数据和接受数据不在同一个进程,这样,这两个进程互不影响。
解决方案如下:服务器端和客户端如下:
当然,若下文要考虑,多个客户端连接同一个服务端时,所以,应该对每个sockt连接开启一个线程。但是对于客户端而言,只要把发送和接受分离即可。所以在客户端中,可以把发送数据和主进程放在一块。如下图:
代码实现如下:
服务器端:
[java] view plaincopyprint?
  1. package com17.tcp;
  2. import java.io.IOException;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. public class MyServer {
  6. public static void main(String[] args) {
  7. try {
  8. ServerSocket ss=new ServerSocket(30000);
  9. while(true)
  10. {
  11. //此行代码会阻塞,将一直等待别人的连接
  12. Socket s=ss.accept();
  13. if(s.isConnected())
  14. {
  15. System.out.println("一个客户端连接此服务器"+s.getInetAddress());
  16. }
  17. //每当客户端连接后启动一条ServerThread线程为该客户端服务
  18. new Thread( new ServerThread(s)).start();
  19. //发送数据到客户端
  20. new Thread(new ServerThread2(s)).start();
  21. }
  22. } catch (IOException e) {
  23. // TODO Auto-generated catch block
  24. e.printStackTrace();
  25. }
  26. }
  27. }
 package com17.tcp;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class MyServer {         public static void main(String[] args) {          try {               ServerSocket ss=new ServerSocket(30000);               while(true)               {                    //此行代码会阻塞,将一直等待别人的连接                    Socket s=ss.accept();                    if(s.isConnected())                    {                         System.out.println("一个客户端连接此服务器"+s.getInetAddress());                    }                    //每当客户端连接后启动一条ServerThread线程为该客户端服务                    new Thread( new ServerThread(s)).start();                  //发送数据到客户端                    new Thread(new ServerThread2(s)).start();               }          } catch (IOException e) {               // TODO Auto-generated catch block               e.printStackTrace();          }     }}

接受数据的并打印的线程:
[html] view plaincopyprint?
  1. package com17.tcp;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintStream;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. public class ServerThread implements Runnable {
  9. //定义当前线程所处理的socket
  10. Socket s=null;
  11. //该线程所处理的socket所对应的输入流
  12. BufferedReader br=null;
  13. public ServerThread(Socket s)
  14. {
  15. try
  16. {
  17. this.s=s;
  18. //初始化socket对应的输入流
  19. br=new BufferedReader(new InputStreamReader(s.getInputStream()));
  20. }
  21. catch(IOException e)
  22. {
  23. e.printStackTrace();
  24. }
  25. }
  26. @Override
  27. public void run() {
  28. try
  29. {
  30. String content=null;
  31. //采用循环不断从Socket中读取客户端发送过来的数据
  32. while((content=readFromClient())!=null)
  33. {
  34. System.out.println("来自客户端消息:"+content);
  35. }
  36. System.out.println("消息:"+content);
  37. PrintStream ps=new PrintStream(s.getOutputStream());
  38. ps.println(br.readLine());
  39. }catch(Exception e)
  40. {
  41. try
  42. {
  43. s.close();
  44. }catch(IOException ex)
  45. {
  46. ex.printStackTrace();
  47. }
  48. }
  49. }
  50. //定义读取客户端数据的方法
  51. private String readFromClient()
  52. {
  53. try
  54. {
  55. return br.readLine();
  56. }
  57. //如果捕捉到异常,表明该socket对应的客户端已经关闭
  58. catch(IOException e)
  59. {
  60. e.printStackTrace();
  61. }
  62. return null;
  63. }
  64. }
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.util.Scanner;public class ServerThread implements Runnable {     //定义当前线程所处理的socket     Socket s=null;     //该线程所处理的socket所对应的输入流     BufferedReader br=null;         public ServerThread(Socket s)     {          try          {               this.s=s;               //初始化socket对应的输入流               br=new BufferedReader(new InputStreamReader(s.getInputStream()));                        }          catch(IOException e)          {               e.printStackTrace();          }         }         @Override     public void run() {         try         {              String content=null;             //采用循环不断从Socket中读取客户端发送过来的数据             while((content=readFromClient())!=null)             {                  System.out.println("来自客户端消息:"+content);             }             System.out.println("消息:"+content);             PrintStream ps=new PrintStream(s.getOutputStream());             ps.println(br.readLine());         }catch(Exception e)         {              try              {                   s.close();              }catch(IOException ex)              {                   ex.printStackTrace();              }         }     }         //定义读取客户端数据的方法     private String readFromClient()     {          try          {               return br.readLine();          }          //如果捕捉到异常,表明该socket对应的客户端已经关闭          catch(IOException e)          {              e.printStackTrace();          }        return null;     }}

发送数据到客户端的线程:
[html] view plaincopyprint?
  1. package com17.tcp;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintStream;
  6. import java.net.Socket;
  7. public class ServerThread2 implements Runnable {
  8. private Socket s;
  9. //用来处理发送数据的
  10. private PrintStream ps=null;
  11. public ServerThread2(Socket s)
  12. {
  13. try
  14. {
  15. this.s=s;
  16. ps=new PrintStream(s.getOutputStream());
  17. }
  18. catch(IOException e)
  19. {
  20. try
  21. {
  22. s.close();
  23. }
  24. catch(IOException ex)
  25. {
  26. ex.printStackTrace();
  27. }
  28. }
  29. }
  30. @Override
  31. public void run() {
  32. try
  33. {
  34. //发送数据到客户端
  35. String line=null;
  36. //不断读取键盘的输入
  37. BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
  38. while((line=br.readLine())!=null)
  39. {
  40. //将用户的键盘输入内容写入socket对应的输出流
  41. ps.println(line);
  42. }
  43. }
  44. catch(IOException e)
  45. {
  46. e.printStackTrace();
  47. }
  48. }
  49. }
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;public class ServerThread2 implements Runnable {     private Socket s;     //用来处理发送数据的     private PrintStream ps=null;     public ServerThread2(Socket s)     {          try          {               this.s=s;               ps=new PrintStream(s.getOutputStream());          }          catch(IOException e)          {               try               {                    s.close();               }               catch(IOException ex)               {                    ex.printStackTrace();               }                        }     }     @Override     public void run() {          try          {                 //发送数据到客户端                  String line=null;                                   //不断读取键盘的输入                  BufferedReader br=new BufferedReader(new InputStreamReader(System.in));                  while((line=br.readLine())!=null)                  {                       //将用户的键盘输入内容写入socket对应的输出流                       ps.println(line);                  }          }          catch(IOException e)          {               e.printStackTrace();          }     }}

效果如下:
但是我们通过以上的代码,要实现这种如下:
虽然上述代码中使用了多线程,每个客户端请求,都会产生一个读线程和写线程。但是也不能完成上图的要求。
为什么呢?
主要在于写的线程。
因为写的线程,虽然捕捉了发送的socket套接字,但是写线程中是时刻监听用户输入System.in。
这样,当多个客户端连接服务器端时,则服务器端有多个线程监听用户输入System.in。但是令人头疼的是,服务器端只有一个dos窗口,而不像客户端一个dos窗口监听一个用户输入System.in。
访问中服务器端结果如下:
所以服务器想通过用户输入形式发送给多个客户端,这种形式是不可行的。
代码中,永远只能发给具有活动的线程。结果不是你想象的那样,发给你想象的线程。
当然,若是服务器不是通过监听用户输入则当然可以实现上述的要求的
我们改一下服务器端:不通过监听用户输入。
服务器端中,接受线程中,一接受到客户的数据,则发送数据。
服务器端,线程如图:
接受线程中修改上述的demo
[html] view plaincopyprint?
  1. //采用循环不断从Socket中读取客户端发送过来的数据
  2. while((content=readFromClient ())!=null )
  3. {
  4. System. out.println( "来自客户端消息:" +content);
  5. ps.println( "客户端"+s.getInetAddress()+"消息已经收入到,消息为:" +content);
  6. }
           //采用循环不断从Socket中读取客户端发送过来的数据        while((content=readFromClient ())!=null )        {              System. out.println( "来自客户端消息:" +content);              ps.println( "客户端"+s.getInetAddress()+"消息已经收入到,消息为:" +content);        }

效果图如下:
【多线程】一对多服务器1<——>N客户端(聊天室)
我想通过上述几个例子,想必对通信的方式已经了解,并且也掌握通信的原理以及通信方法。
那我们再说,聊天室通信,就是类似我们qq群。一人发表了看法,则其他的人都能看到此消息。
猜想qq实现方式,就是通过服务器转发【仅此个人看法】
那我们这个例子实现方式如下图:
那这个例子 不在贴代码,我们说一下思路,在服务器端有个列表,专门用来保存客户端的socket。只要客户端连接服务器,就把客户端的socket添加到服务器列表中。当接受到任何客户端数据时,就把数据转发给列表中任何一个客户端socket。
部分代码如下:
[html] view plaincopyprint?
  1. //采用循环不断从Socket中读取客户端发送过来的数据
  2. while((content=readFromClient())!= null)
  3. {
  4. //便利socketList中的每一个socket
  5. //将读到的内容向每个socket发送一次
  6. for(Socket s:MyServer. socketList)
  7. {
  8. PrintStream ps= new PrintStream(s.getOutputStream());
  9. ps.println(content);
  10. }
  11. }
原创粉丝点击