Socket加入多线程通信实现简单的CS聊天室

多线程就是考虑到不可以用传统的BufferReader的readline()方法读取数据,因为会引起现场阻塞。服务器端要开两个线程,一个负责创ServerSocket监听,另一个负责处理Socket通信的线程类。客户端也需要开两个线程,一个负责主界面响应用户输入,另一个负责读取Socket对应输入流中的数据,并将数据显示出来。

我们要实现的功能就是从客户端发送信息给服务器,然后服务器再把信息转发回到客户端,这是一个非常简单的功能,不说那么多直接上代码。

服务器端(Tomcat7.0,Eclipse)

服务器端有两个类一个类负责监听它的代码如下:

public class MyServer {
		//定义保存所有的Socket的ArrayList
	public static ArrayList socketList=new ArrayList();
	public static void main(String[] args)
			throws IOException {
		ServerSocket ss = new ServerSocket(30000);
		while (true) {
			//此段代码会阻塞,将一直等待别人的连接
			Socket s = ss.accept();
			//每有一个连接就将它加入到socketList里面(ArrayList数组列表)
			socketList.add(s);
			//当客户端启动后,就会启动一条ServerThread线程为该客户端服务
			new Thread(new ServerThread(s)).start();
		}
	}
}
另一个负责网络连接,以及转发:
public void run(){
	try{
		String content = null;
		//只要从客户端读到的数据不为空,也就是循环的从Socket中读取客户端发过来的数据
		while ((content = readFromClient()) !=null) {
			System.out.println("---" + Arrays.toString(content.getBytes("utf-8")));
			System.out.println("---" + content);
			// 遍历socketList中的每个Socket,
			// 将读到的内容向每个Socket发送一次
			
			for (Iterator it = MyServer.socketList.iterator();it.hasNext();) 
			{
				Socket s = it.next();
				try {
					OutputStream os = s.getOutputStream();
					//把数据写进content
					os.write((content+ "\n").getBytes("utf-8"));
				} catch (Exception e) {
					e.printStackTrace();
					// 删除该Socket。
					it.remove();
					System.out.println(MyServer.socketList);
				}	
			}
		}	
	}catch(IOException e){
		e.printStackTrace();
	}}
	private String readFromClient()
	{
		try {
			return br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
			// 只要有异常就,有异常肯定说明对应的客户端关闭了,删除该Socket。
			MyServer.socketList.remove(s); 
		}
		return null;
	}
}

 客户端代码

客户端也有两个类,一个负责主界面响应用户输入,另一个负责读取Socket对应输入流中的数据,并将数据显示出来。

public class MainActivity extends Activity
{
   // 定义界面上的两个文本框
   EditText input;
   TextView show;
   // 定义界面上的一个按钮
   Button send;
   Handler handler;
   // 定义与服务器通信的子线程
   ClientThread clientThread;
   @Override
   public void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      input = (EditText) findViewById(R.id.input);
      send = (Button) findViewById(R.id.send);
      show = (TextView) findViewById(R.id.show);
      handler = new Handler() // ②
      {
         @Override
         public void handleMessage(Message msg)
         {
            // 如果消息来自于子线程
            if (msg.what == 0x123)
            {
               // 将读取的内容追加显示在文本框中
               show.append("\n" + msg.obj.toString());
            }
         }
      };
      clientThread = new ClientThread(handler);
      // 客户端启动ClientThread线程创建网络连接、读取来自服务器的数据
      new Thread(clientThread).start(); // ①
      send.setOnClickListener(new OnClickListener()
      {
         @Override
         public void onClick(View v)
         {
            try
            {
               // 当用户按下发送按钮后,将用户输入的数据封装成Message
               // 然后发送给子线程的Handler
               Message msg = new Message();
               msg.what = 0x345;
               msg.obj = input.getText().toString();
               clientThread.revHandler.sendMessage(msg);
               // 清空input文本框
               input.setText("");
            }
            catch (Exception e)
            {
               e.printStackTrace();
            }
         }
      });
   }
}

另一个是

public ClientThread(Handler handler)
   {
      this.handler = handler;
   }
   public void run()
   {
      try
      {
         s = new Socket("192.168.43.146", 30000);
         br = new BufferedReader(new InputStreamReader(
               s.getInputStream()));
         os = s.getOutputStream();
         // 启动一条子线程来读取服务器响应的数据
         new Thread()
         {
            @Override
            public void run()
            {
               String content = null;
               // 不断读取Socket输入流中的内容
               try
               {
                  while ((content = br.readLine()) != null)
                  {
                     // 每当读到来自服务器的数据之后,发送消息通知程序
                     // 界面显示该数据
                     Message msg = new Message();
                     msg.what = 0x123;
                     msg.obj = content;
                     handler.sendMessage(msg);
                  }
               }
               catch (IOException e)
               {
                  e.printStackTrace();
               }
            }
         }.start();
         // 为当前线程初始化Looper
         Looper.prepare();
         // 创建revHandler对象
         revHandler = new Handler()
         {
            @Override
            public void handleMessage(Message msg)
            {
               // 接收到UI线程中用户输入的数据
               if (msg.what == 0x345)
               {
                  // 将用户在文本框内输入的内容写入网络
                  try
                  {
                     os.write((msg.obj.toString() + "\r\n")
                           .getBytes("utf-8"));
                  }
                  catch (Exception e)
                  {
                     e.printStackTrace();
                  }
               }
            }
         };
         // 启动Looper
         Looper.loop();
      }
      catch (SocketTimeoutException e1)
      {
         System.out.println("网络连接超时!!");
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }
}
运行效果如下:
服务器端: 
  
Socket加入多线程通信实现简单的CS聊天室_第1张图片

你可能感兴趣的:(Android网络应用,多线程,聊天室,Socket)