在Android中利用Socket实现的聊天室(TCP)



         最近研究了一下Java中的socket通信机制,由于英语水平不好,只能习惯性的百度、谷歌上找相关类文章,总是有一些收获的,也遇到了不少小困难(其实是对这些机制不了解),现在写下来。

        顺便说一下,网上的那些源代码都是复制来复制去,照样写上去总是不能正常运行,是他们的错的还是我写的是错的?

下面是一些最基本的东西,网上总结的。

 端口 :端口是将应用程序与IP网络相关联,是应用进程的地址标识。分为两种公用端口(0~1023)和临时端口(1024~65535),我们用的就是临时端口。

套接字:区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。Socket原意是“插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

 

 流:Java中的流分为两种,一种是字节流(8位),另一种是字符流(16),分别由四个抽象类来表示:InputStream,OutputStream,Reader,Writer。 

          InputStream/OutputStream:

                             是所有的输入和输入类的基类。 
                             面向字节形式的I/O操作(8位字节流)。 
          Reader/Writer:

                             面向字符的I/O操作(16位的Unicode字符,在JAVA语言中,byte类型是8位的,char类型是16位的,所以在处理中文的时候需要用Reader和Writer  

InputStreamReader:可以将InputStream转换为Reader 
OutputStreamWriter:可以将OutputStream转换为Writer 

关于TCP的三次握手可以看这个:http://www.cnblogs.com/rootq/articles/1377355.html

基于TCP的聊天室

下面是效果图:

客户端将消息发往服务端用的是字节流,服务器端发往客户端用的是字符流。

Client客户端代码:

开启一个ServerSocket监听一个端口

/**
 * 服务器端 *
 */
public class Server {
	
	private ServerSocket sock ;
	private String str ;
	private List<Socket> sockLi = new ArrayList<Socket>();
	private String conte = null;//当前接收到的信息
	public Server()
	{
		try {
			//* 创建ServerSocket负责接收客户连接请求
			sock = new ServerSocket(5171,3);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void beginServer()
	{
		while(true)
		{
			try {
				Socket soc = sock.accept() ;
				sockLi.add(soc);
				//开启线程
				new Thread(new Serv(soc)).start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	private class Serv implements Runnable{
		
		private Socket soc ;
		
		public Serv(Socket so)
		{
			this.soc = so;
		}
		@Override
		public void run() {
			try {
			InputStream instr = soc.getInputStream();
			while(!soc.isClosed()){
				//从流中读取下一个字节
				int len = instr.read();	
				//从字节流中读取信息
				byte[] bt = new byte[len];
				instr.read(bt, 0, len);
				str = new String(bt);
			
				if(str.equals("end"))
				{
					Thread.sleep(200);
					soc.close();
					sockLi.remove(soc);
					break ;
				}
				else if(str.trim().equals(""))
				{
					continue ;
				}
				else 
				{
					conte = str;
					sendMessage();
				}
			}
				
			} catch (IOException e) {
				//连接断开
				sockLi.remove(soc);
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}	
		}
		
	}
	
	private void sendMessage()
	{
		PrintWriter pr;
		for(Socket so:sockLi)
		{
			try {
				pr = new PrintWriter(so.getOutputStream(),true);
				pr.print(conte+"\n");
				pr.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args)
	{
		Server se = new Server();
		se.beginServer();
	}
}
  提一下 readline和read都会阻塞进程,readline遇到\n会返回,所以在客户端发送消息后要发送一个\n表示已经发送完。 客户端:具体操作类ScoketSend
public class SocketSend {
	
	public static void main(String[] args)
	{
	}

	private Handler hd ;
	private BufferedReader buf ;
	static Socket sock ;
	private Bundle bun;
	private String name ;
	public SocketSend(Handler hd,String name)
	{
		this.name = name ;
		this.hd = hd ;
		try {
			sock = new Socket();
			bun = new Bundle();
			//android中的本地地址为10.0.2.2
			InetSocketAddress isa = 
				new InetSocketAddress("10.0.2.2", 5171); 
			sock.connect(isa, 300);//如果300ms没有连接到就会失败
			buf = new BufferedReader(
				new InputStreamReader(sock.getInputStream()));
			
			new Thread(new messtake(buf)).start();
			
		
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private class messtake implements Runnable{
		private BufferedReader bu= null ;
		public messtake(BufferedReader buf)
		{
			bu = buf ;
		}
		@Override
		public void run() {
			String msg ="";
			try {
			while ((msg = bu.readLine()) != null) {
				if(msg.trim().equals(""))
				{//这里会接收到一个空白字符串,还不知道为什么 !
					continue;
				}
		    	//先把字符串中原本的/n替换掉,客户端接收再替换过来
			//一下是android部分通知ui更新
                    	bun.putString("contentMess", 
		   	msg.replace("Sun948040237", "\n"));
                    	bun.putInt("type", 1);
                    	Message message = new Message();
                    	message.setData(bun);
                    	hd.sendMessage(message); 
	            	}  
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	//向服务器发送消息
	public void send(String content)
	{
		try {
			content = name+"&#&" +content ;
			OutputStream ou = sock.getOutputStream();
			ou.write(content.getBytes().length);
			ou.write(content.getBytes());
			ou.flush();
			
		} catch (IOException e) {
			bun.putString("contentMess", "发送失败:"+content);
            bun.putInt("type", 0);
            Message message = new Message();
			message.setData(bun);
            hd.sendMessage(message); 
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
 
 客户端调用的时候

//NAME是昵称 

String con = "苹果";
new SocketSend(myHandler,NAME).send(con.replace("\n", "Sun948040237")+"\n");

下面是下载示例的链接

http://pan.baidu.com/s/1GbbK8

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自sunluo948040237.iteye.com/blog/1960218