Android实现基于TCP和UDP协议的即时通讯,含android端和服务器端

这几天学习了下在android中实现即时通讯的方法,一开始,自然是从基本的网络协议中开始尝试了,这样能够最大化的私人订制自己的应用,还能学习到更多的知识,好处多多,接下来就简单介绍下两种协议的不同点吧

TCP协议:提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。就如给悬崖上的两人通信时,他必须先把桥建好,确认桥是没问题的情况下,才把信件交过去,以后大家每次通信时,都确认下桥没什么问题,再通过这座桥来回通信了。

UDP协议:不为IP提供可靠性、流控或差错恢复功能,在正式通信前不必与对方先建立连接,不管对方状态就直接发送。这个就是飞鸽传书了~

虽然UDP可靠性不如TCP协议,但是通信效率高于TCP。在网速极差的情况下优先考虑UDP协议,网速好的话TCP还是很方便使用的。

在Java中使用TCP可以通过java.net.Socket;这个类

首先,创建一个Socket实例,并建立连接,该处不使用new Socket(int port)创建实例,该方法将绑定一个端口,以后发送信息,监听都是使用该端口,如果该端口被占用了,就会引发异常。

  1. //实例化一个Socket对象  
  2. socket = new Socket();  
  3. //与对应的ip、端口的服务器进行连接,先要把桥建好  
  4. socket.connect(new InetSocketAddress(ip, port), 3000);  

接收信息

  1. InputStream ois = socket.getInputStream();  
  2. DataInputStream dis = new DataInputStream(new BufferedInputStream(ois));  
  3. //读取服务器发过来的信息,如果没信息将会阻塞线程  
  4. msg =  dis.readUTF();  

发送信息

  1. //获得输出流  
  2. DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));  
  3. //发送数据  
  4. dos.writeUTF(msg);  

接下来上源码,为三个Thread的子类,分别对应上面三个

Socket和其他基本信息的初始化,直接使用此类发送消息,设置消息监听

  1. public class SocketThread extends Thread{  
  2.   
  3.     private Socket socket;  
  4.     private Client client;  
  5.     private String ip;  
  6.     private int port;  
  7.     private boolean isStart=false;  
  8.     private MessageListener mMessageListener;  
  9.       
  10.     /** 
  11.      *  
  12.      * 使用TCP协议,连接访问 
  13.      * @param ip 目标机器的IP 
  14.      * @param port 端口 
  15.      * @param mMessageListener 收到服务器端数据时将回调该接口内的 
  16.      *  public void Message(String msg)方法 
  17.      */  
  18.     public SocketThread(String ip, int port,  
  19.             MessageListener mMessageListener) {  
  20.         this.ip = ip;  
  21.         this.port = port;  
  22.         this.mMessageListener = mMessageListener;  
  23.     }  
  24.   
  25.     public void run() {  
  26.         try {  
  27.             //实例化一个Socket对象  
  28.             socket = new Socket();  
  29.             //与对应的ip、端口进行连接,先要把桥建好  
  30.             socket.connect(new InetSocketAddress(ip, port), 3000);  
  31.             if (socket.isConnected()) {  
  32.                 System.out.println("Connected..");  
  33.                 client = new Client(socket,mMessageListener);  
  34.                 //打开对应的输入/输出流监听  
  35.                 client.start();  
  36.                 isStart=true;  
  37.             }  
  38.         } catch (IOException e) {  
  39.             e.printStackTrace();  
  40.             isStart=false;  
  41.         }  
  42.     }  
  43.   
  44.     // 直接通过client得到读线程  
  45.     public ClientInputThread getClientInputThread() {  
  46.         return client.getIn();  
  47.     }  
  48.   
  49.     // 直接通过client得到写线程  
  50.     public ClientOutputThread getClientOutputThread() {  
  51.         return client.getOut();  
  52.     }  
  53.   
  54.     //返回Socket状态  
  55.     public boolean isStart(){  
  56.         return isStart;  
  57.     }  
  58.       
  59.     // 直接通过client停止读写消息  
  60.     public void setIsStart(boolean isStart) {  
  61.         this.isStart = isStart;  
  62.         client.getIn().setStart(isStart);  
  63.         client.getOut().setStart(isStart);  
  64.     }  
  65.       
  66.     //发送消息  
  67.     public void sendMsg(String msg){  
  68.         client.getOut().sendMsg(msg);  
  69.     }  
  70.       
  71.     public class Client {  
  72.   
  73.         private ClientInputThread in;  
  74.         private ClientOutputThread out;  
  75.   
  76.         public Client(Socket socket,MessageListener mMessageListener) {  
  77.             //用这个监听输入流线程来接收信息  
  78.             in = new ClientInputThread(socket);  
  79.             in.setMessageListener(mMessageListener);  
  80.             //以后就用这个监听输出流的线程来发送信息了  
  81.             out = new ClientOutputThread(socket);  
  82.         }  
  83.   
  84.         public void start() {  
  85.             in.setStart(true);  
  86.             out.setStart(true);  
  87.             in.start();  
  88.             out.start();  
  89.         }  
  90.   
  91.         // 得到读消息线程  
  92.         public ClientInputThread getIn() {  
  93.             return in;  
  94.         }  
  95.   
  96.         // 得到写消息线程  
  97.         public ClientOutputThread getOut() {  
  98.             return out;  
  99.         }  
  100.     }  
  101. }  
接收信息的实现类
  1. public class ClientInputThread extends Thread {  
  2.     private Socket socket;  
  3.     private String msg;  
  4.     private boolean isStart = true;  
  5.     private InputStream ois;  
  6.     private DataInputStream dis;  
  7.     private MessageListener messageListener;// 消息监听接口对象  
  8.   
  9.     public ClientInputThread(Socket socket) {  
  10.         this.socket = socket;  
  11.         try {  
  12.             ois = socket.getInputStream();  
  13.             dis = new DataInputStream(new BufferedInputStream(ois));  
  14.         } catch (IOException e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.     }  
  18.   
  19.     /** 
  20.      * 提供给外部的消息监听方法 
  21.      *  
  22.      * @param messageListener 
  23.      *            消息监听接口对象 
  24.      */  
  25.     public void setMessageListener(MessageListener messageListener) {  
  26.         this.messageListener = messageListener;  
  27.     }  
  28.   
  29.     public void setStart(boolean isStart) {  
  30.         this.isStart = isStart;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void run() {  
  35.         try {  
  36.             while (isStart) {  
  37.                 //读取信息,如果没信息将会阻塞线程  
  38.                 msg =  dis.readUTF();  
  39.                 // 每收到一条消息,就调用接口的方法Message(String msg)  
  40.                 Log.v("收到消息", msg);  
  41.                 messageListener.Message(msg);  
  42.             }  
  43.             ois.close();  
  44.             if (socket != null)  
  45.                 socket.close();  
  46.         } catch (IOException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.     }  
  50.       
  51.     BufferedReader reader=null;  
  52.     public String getInputStreamString() {  
  53.         /* 
  54.          * To convert the InputStream to String we use the 
  55.          * BufferedReader.readLine() method. We iterate until the BufferedReader 
  56.          * return null which means there's no more data to read. Each line will 
  57.          * appended to a StringBuilder and returned as String. 
  58.          */  
  59.         if (ois != null) {  
  60.             reader = new BufferedReader(new InputStreamReader(ois));  
  61.         }  
  62.         StringBuilder sb = new StringBuilder();  
  63.   
  64.         String line = null;  
  65.         try {  
  66.             while ((line = reader.readLine()) != null) {  
  67.                 sb.append(line + "\n");  
  68.             }  
  69.         } catch (IOException e) {  
  70.             e.printStackTrace();  
  71.         }   
  72.   
  73.         return sb.toString();  
  74.     }  
  75. }  
发送信息的实现类
  1. public class ClientOutputThread extends Thread {  
  2.     private Socket socket;  
  3.     private DataOutputStream dos;  
  4.     private boolean isStart = true;  
  5.     private String msg;  
  6.   
  7.     public ClientOutputThread(Socket socket) {  
  8.         this.socket = socket;  
  9.         try {  
  10.             dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));  
  11.         } catch (IOException e) {  
  12.             e.printStackTrace();  
  13.         }  
  14.     }  
  15.   
  16.     public void setStart(boolean isStart) {  
  17.         this.isStart = isStart;  
  18.     }  
  19.   
  20.     // 这里处理跟服务器是一样的  
  21.     public void sendMsg(String msg) {  
  22.         this.msg = msg;  
  23.         synchronized (this) {  
  24.             notifyAll();  
  25.         }  
  26.     }  
  27.   
  28.     @Override  
  29.     public void run() {  
  30.         try {  
  31.             while (isStart) {  
  32.                 if (msg != null) {  
  33.                     dos.writeUTF(msg);  
  34.                     dos.flush();  
  35.                     msg=null;  
  36.                     synchronized (this) {  
  37.                         wait();// 发送完消息后,线程进入等待状态  
  38.                     }  
  39.                 }  
  40.             }  
  41.             dos.close();// 循环结束后,关闭输出流和socket  
  42.             if (socket != null)  
  43.                 socket.close();  
  44.         } catch (InterruptedException e) {  
  45.             e.printStackTrace();  
  46.         } catch (IOException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.     }  
  50.   
  51. }  
  1. //定义接收到消息时的,处理消息的接口  
  2. public interface MessageListener {  
  3.     public void Message(String msg);  
  4. }  

主界面,感觉很丑,将就吧

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context="com.example.chatclient.MainActivity" >  
  10.   
  11.   
  12.     <ScrollView  
  13.         android:id="@+id/svMessage"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="100dp" >  
  16.   
  17.         <TextView  
  18.             android:id="@+id/tvMessage"  
  19.             android:layout_width="wrap_content"  
  20.             android:layout_height="wrap_content"  
  21.             android:text="消息内容:\n" />  
  22.     </ScrollView>  
  23.   
  24.     <EditText  
  25.         android:id="@+id/etMessage"  
  26.         android:layout_width="100dp"  
  27.         android:layout_height="wrap_content"  
  28.         android:layout_below="@+id/svMessage" />  
  29.   
  30.     <TextView  
  31.         android:id="@+id/tvSend"  
  32.         android:layout_width="wrap_content"  
  33.         android:layout_height="wrap_content"  
  34.         android:layout_below="@+id/svMessage"  
  35.         android:layout_marginLeft="10dp"  
  36.         android:layout_toRightOf="@+id/etMessage"  
  37.         android:text="发送消息"  
  38.         android:textSize="25sp" />  
  39. "  
  40.   
  41. </RelativeLayout>  

MainActivity代码
  1. public class MainActivity extends Activity {  
  2.   
  3.     EditText etMessage;  
  4.     TextView tvSend, tvMessage;  
  5.     SocketThread client;  
  6.     MyHandler myHandler;  
  7.   
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.activity_main);  
  12.         setup();  
  13.     }  
  14.   
  15.     public void setup() {  
  16.         etMessage = (EditText) findViewById(R.id.etMessage);  
  17.         tvSend = (TextView) findViewById(R.id.tvSend);  
  18.         tvMessage = (TextView) findViewById(R.id.tvMessage);  
  19.         tvSend.setOnClickListener(onClick);  
  20.         myHandler = new MyHandler();  
  21.   
  22.         //初始化  
  23.         client = new SocketThread("10.21.56.226"8888,new MessageListener() {  
  24.   
  25.                     //收到消息后调用此方法  
  26.                     @Override  
  27.                     public void Message(String msg) {  
  28.                         // TODO Auto-generated method stub  
  29.                         // tvMessage.append(msg);  
  30.                         Bundle bundle = new Bundle();  
  31.                         bundle.putString("input", msg);  
  32.                         Message isMessage = new Message();  
  33.                         isMessage.setData(bundle);  
  34.                         //使用handler转发  
  35.                         myHandler.sendMessage(isMessage);  
  36.                     }  
  37.                 });  
  38.         //正式启动线程  
  39.         client.start();  
  40.   
  41.     }  
  42.   
  43.     OnClickListener onClick = new OnClickListener() {  
  44.         public void onClick(android.view.View v) {  
  45.             String message = etMessage.getText().toString();  
  46.             Log.v("发送消息", message);  
  47.             if (client.isStart()) {  
  48.                 client.sendMsg(message);  
  49.             }  
  50.         };  
  51.     };  
  52.   
  53.     private class MyHandler extends Handler {  
  54.         @Override  
  55.         public void handleMessage(Message msg) {  
  56.             // TODO Auto-generated method stub  
  57.             Log.v("处理收到的消息""  ");  
  58.             tvMessage.append(msg.getData().getString("input"));  
  59.         }  
  60.     }  
  61. }  


服务器端的代码,主要是使用ServerSocket监听一个端口,来与客户端链接和收发信息
  1. public class ChatServer {  
  2.     boolean started = false;  
  3.     ServerSocket ss = null;  
  4.   
  5.     List<Client> clients = new ArrayList<Client>();  
  6.   
  7.     public static void main(String[] args) {  
  8.     new ChatServer().start();  
  9.     }  
  10.   
  11.     public void start() {  
  12.     try {  
  13.         //ServerSocket监听8888端口  
  14.         ss = new ServerSocket(8888);  
  15.         started = true;  
  16.     } catch (BindException e) {  
  17.         System.out.println("start....");  
  18.         System.out.println("有问题");  
  19.         e.printStackTrace();  
  20.         System.exit(0);  
  21.     } catch (IOException e) {  
  22.         e.printStackTrace();  
  23.     }  
  24.   
  25.     try {  
  26.   
  27.         while (started) {  
  28.         Socket s = ss.accept();  
  29.         Client c = new Client(s);  
  30.         System.out.println("a client connected!");  
  31.         new Thread(c).start();  
  32.         clients.add(c);  
  33.         // dis.close();  
  34.         }  
  35.     } catch (IOException e) {  
  36.         e.printStackTrace();  
  37.     } finally {  
  38.         try {  
  39.         ss.close();  
  40.         } catch (IOException e) {  
  41.         // TODO Auto-generated catch block  
  42.         e.printStackTrace();  
  43.         }  
  44.     }  
  45.     }  
  46.   
  47.     class Client implements Runnable {  
  48.     private Socket s;  
  49.     private DataInputStream dis = null;  
  50.     private DataOutputStream dos = null;  
  51.     private boolean bConnected = false;  
  52.   
  53.     public Client(Socket s) {  
  54.         this.s = s;  
  55.         try {  
  56.         dis = new DataInputStream(s.getInputStream());  
  57.         dos = new DataOutputStream(s.getOutputStream());  
  58.         bConnected = true;  
  59.         } catch (IOException e) {  
  60.         e.printStackTrace();  
  61.         }  
  62.     }  
  63.   
  64.     public void send(String str) {  
  65.         try {  
  66.         dos.writeUTF(str);  
  67.         } catch (IOException e) {  
  68.         clients.remove(this);  
  69.         System.out.println("关闭一个连接");  
  70.         // e.printStackTrace();  
  71.         }  
  72.     }  
  73.   
  74.     public void run() {  
  75.         try {  
  76.         while (bConnected) {  
  77.             String str = dis.readUTF();  
  78.             System.out.println(str);  
  79.             for (int i = 0; i < clients.size(); i++) {  
  80.             Client c = clients.get(i);  
  81.             c.send(str);  
  82.             // System.out.println(" a string send !");  
  83.             }  
  84.             /* 
  85.              * for(Iterator<Client> it = clients.iterator(); 
  86.              * it.hasNext(); ) { Client c = it.next(); c.send(str); } 
  87.              */  
  88.             /* 
  89.              * Iterator<Client> it = clients.iterator(); 
  90.              * while(it.hasNext()) { Client c = it.next(); c.send(str); 
  91.              * } 
  92.              */  
  93.         }  
  94.         } catch (EOFException e) {  
  95.         System.out.println("Client closed!");  
  96.         } catch (IOException e) {  
  97.         e.printStackTrace();  
  98.         } finally {  
  99.         try {  
  100.             System.out.println("close All !");  
  101.             if (dis != null)  
  102.             dis.close();  
  103.             if (dos != null)  
  104.             dos.close();  
  105.             if (s != null) {  
  106.             s.close();  
  107.             // s = null;  
  108.             }  
  109.   
  110.         } catch (IOException e1) {  
  111.             e1.printStackTrace();  
  112.         }  
  113.   
  114.         }  
  115.     }  
  116.   
  117.     }  
  118. }  
接下来先运行服务器代码,再运行手机端就可以了,多台手机可以互相发送信息了。


接下来写下UDP的发送和接收,服务器端也进行了转发,使得一台手机发送的消息,所有手机都能收到消息

UDP使用的是DatagramSocket类,从该类名字就可以看出该类使用起来类似于电报或是信件这样的形式

(1)创建一个DatagramSocket实例,该处也不固定端口了

client = new DatagramSocket();

(2)发送数据需要先把"信"写好,这里和TCP不太同,使用的是DatagramPacket来包含发送的地址和发送的数据

创建DatagramPacket实例

DatagramPacket(byte[] buf, int offset, int length,InetAddress address, int port)
再调用DatagramSocket.send(DatagramPacket pack);

(3)接收数据,就不用知道对方地址了,所以一般使用DatagramPacket packet = new DatagramPacket(rbyte[] buf, int offset, int length);

然后调用DatagramSocket.receive(DatagramPacket packet);接收数据

Socket和其他基本信息的初始化,直接使用此类发送消息,设置消息监听

  1. /** 
  2.  * @author xuan 2014-10-30 
  3.  *  
  4.  *         使用UDP发送数据的类,收发数据一般直接使用该类 
  5.  */  
  6. public class UDPThread extends Thread {  
  7.   
  8.     private String IP;  
  9.     private int port;  
  10.     private DatagramSocket client;  
  11.     private ReceivePacket mReceivePacket;  
  12.     private MessageListener mMessageListener;  
  13.     // 第一次发送给服务器的数据  
  14.     private String connetString;  
  15.     // 服务器地址  
  16.     // private InetAddress mInetAddress;  
  17.     byte[] baMessage = null;  
  18.     // 判断服务是否可以使用  
  19.     private boolean isStart;  
  20.     // 是否使用WifiManager.MulticastLock  
  21.     private boolean useWifyLock = false;  
  22.     public WifiManager.MulticastLock lock;  
  23.   
  24.     public UDPThread(String IP, int port, String connetString,  
  25.             MessageListener messageListener) {  
  26.         // TODO Auto-generated constructor stub  
  27.         this.IP = IP;  
  28.         this.port = port;  
  29.         this.connetString = connetString;  
  30.         this.mMessageListener = messageListener;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void run() {  
  35.         // TODO Auto-generated method stub  
  36.         try {  
  37.             //  
  38.             if (useWifyLock) {  
  39.                 lock.acquire();  
  40.             }  
  41.             client = new DatagramSocket();  
  42. //          client.setBroadcast(true);  
  43.             byte[] msg = String2Byte(connetString);  
  44.             DatagramPacket packet = new DatagramPacket(msg, msg.length,  
  45.                     InetAddress.getByName(IP), port);  
  46.             client.send(packet);  
  47.             mReceivePacket = new ReceivePacket(client);  
  48.             mReceivePacket.setMessageListener(mMessageListener);  
  49.             mReceivePacket.lock = this.lock;  
  50.             mReceivePacket.start();  
  51.             isStart = true;  
  52.             // 本线程以后将等待并响应发送消息的请求(sendMessage(String))  
  53.             waitMessageToSend();  
  54.         } catch (Exception e) {  
  55.             // TODO Auto-generated catch block  
  56.             e.printStackTrace();  
  57.         }  
  58.         if (useWifyLock) {  
  59.             lock.release();  
  60.         }  
  61.     }  
  62.   
  63.     public void sendMessage(String msg) {  
  64.   
  65.         synchronized (this) {  
  66.             baMessage = String2Byte(msg);  
  67.             notifyAll();  
  68.         }  
  69.   
  70.     }  
  71.   
  72.     // 部分手机默认关闭UDP广播功能,此时必须使用该方法  
  73.     public void useWifyLock(WifiManager.MulticastLock lock) {  
  74.         if (lock != null) {  
  75.             useWifyLock = true;  
  76.             mReceivePacket.useWifyLock=true;  
  77.             this.lock = lock;  
  78.         }  
  79.     }  
  80.   
  81.     private void waitMessageToSend() {  
  82.         while (isStart) {  
  83.             // 因为只有一条发送线程,所以不用放在synchronized块中,可提高响应度  
  84.             if (baMessage != null) {  
  85.                 DatagramPacket packet;  
  86.                 try {  
  87.                     if (useWifyLock) {  
  88.                         lock.acquire();  
  89.                     }  
  90.   
  91.                     packet = new DatagramPacket(baMessage, baMessage.length,  
  92.                             InetAddress.getByName(IP), port);  
  93.                     client.send(packet);  
  94.                 } catch (Exception e) {  
  95.                     // TODO Auto-generated catch block  
  96.                     e.printStackTrace();  
  97.                 }  
  98.                 System.out.println("msg长度: " + baMessage.length);  
  99.                 baMessage = null;  
  100.                 if (useWifyLock) {  
  101.                     lock.release();  
  102.                 }  
  103.             }  
  104.   
  105.             synchronized (this) {  
  106.                 try {  
  107.                     wait();  
  108.                 } catch (InterruptedException e) {  
  109.                     // TODO Auto-generated catch block  
  110.                     e.printStackTrace();  
  111.                 }  
  112.             }  
  113.         }  
  114.         if (!client.isClosed()) {  
  115.             client.close();  
  116.         }  
  117.     }  
  118.   
  119.     public void setStart(boolean isStart) {  
  120.         this.isStart = isStart;  
  121.     }  
  122.   
  123.     public void close() {  
  124.         this.isStart = false;  
  125.         mReceivePacket.startReceive(false);  
  126.     }  
  127.   
  128.     private byte[] String2Byte(String message) {  
  129.         ByteArrayOutputStream ostream = new ByteArrayOutputStream();  
  130.         DataOutputStream dataStream = new DataOutputStream(ostream);  
  131.         try {  
  132.             dataStream.writeUTF(message);  
  133.   
  134.         } catch (IOException e) {  
  135.             // TODO Auto-generated catch block  
  136.             e.printStackTrace();  
  137.         }  
  138.         try {  
  139.             dataStream.close();  
  140.         } catch (IOException e) {  
  141.             // TODO Auto-generated catch block  
  142.             e.printStackTrace();  
  143.         }  
  144.         return ostream.toByteArray();  
  145.   
  146.     }  
  147.   
  148. }  

监听服务端发送过来的数据的实现类

  1. /** 
  2.  * @author xuan 2014-10-30 
  3.  *  
  4.  *         接收数据的类 
  5.  */  
  6. public class ReceivePacket extends Thread {  
  7.   
  8.     private DatagramSocket server;  
  9.     private MessageListener mMessageListener;  
  10.     // 最多接受1024byte数据  
  11.     private byte[] recive = new byte[1024];  
  12.     private boolean isStart = false;  
  13.   
  14.     boolean useWifyLock = false;  
  15.     public WifiManager.MulticastLock lock;  
  16.   
  17.     public ReceivePacket(DatagramSocket server) {  
  18.         // TODO Auto-generated constructor stub  
  19.         this.server = server;  
  20.     }  
  21.   
  22.     @Override  
  23.     public void run() {  
  24.         // TODO Auto-generated method stub  
  25.         isStart = true;  
  26.         receive();  
  27.     }  
  28.   
  29.     private void receive() {  
  30.   
  31.         try {  
  32.             while (isStart) {  
  33.                 DatagramPacket packet = new DatagramPacket(recive,  
  34.                         recive.length);  
  35.   
  36.                 // 阻塞接收,直到接收到数据为止才继续  
  37.                 Log.v("等待数据""  \n");  
  38.                 if (useWifyLock) {  
  39.                     lock.acquire();  
  40.                 }  
  41.                 server.receive(packet);  
  42.   
  43.                 Log.v("收到数据了""  \n");  
  44.   
  45.                 // 收到数据后,调用MessageListener  
  46.                 if(isStart){  
  47.                     mMessageListener.message(byte2String(recive));  
  48.                 }  
  49.                 if (useWifyLock) {  
  50.                     lock.release();  
  51.                 }  
  52.             }  
  53.         } catch (Exception e) {  
  54.             // TODO Auto-generated catch block  
  55.             e.printStackTrace();  
  56.         }  
  57.         if (!server.isClosed()) {  
  58.             server.close();  
  59.         }  
  60.   
  61.     }  
  62.   
  63.     public void startReceive(boolean start) {  
  64.         this.isStart = start;  
  65.     }  
  66.   
  67.     /** 
  68.      * 提供给外部的消息监听方法 
  69.      *  
  70.      * @param messageListener 
  71.      *            消息监听接口对象 
  72.      */  
  73.     public void setMessageListener(MessageListener messageListener) {  
  74.         this.mMessageListener = messageListener;  
  75.     }  
  76.   
  77.     private String byte2String(byte[] msg) {  
  78.         DataInputStream istream = new DataInputStream(new ByteArrayInputStream(  
  79.                 msg, 0, msg.length));  
  80.         String str = null;  
  81.         try {  
  82.             str = istream.readUTF();  
  83.         } catch (IOException e) {  
  84.             // TODO Auto-generated catch block  
  85.             e.printStackTrace();  
  86.         }  
  87.         return str;  
  88.     }  
  89.   
  90. }  
MainActivity类代码

  1. public class MainActivity extends Activity {  
  2.   
  3.     EditText etMessage;  
  4.     TextView  tvMessage;  
  5.     Button tvSend,btClose,btStart;  
  6.     UDPThread client;  
  7.     // ClientInputThread mClientInputThread;  
  8.     // ClientOutputThread mClientOutputThread;  
  9.     MyHandler myHandler;  
  10.   
  11.     WifiManager.MulticastLock lock;  
  12.       
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.activity_main);  
  17.         setup();  
  18.     }  
  19.   
  20.     public void setup() {  
  21.         etMessage = (EditText) findViewById(R.id.etMessage);  
  22.         tvSend = (Button) findViewById(R.id.tvSend);  
  23.         tvMessage = (TextView) findViewById(R.id.tvMessage);  
  24.         btClose = (Button)findViewById(R.id.btClose);  
  25.         btStart = (Button)findViewById(R.id.btStart);  
  26.         tvSend.setOnClickListener(onClick);  
  27.         btClose.setOnClickListener(onClick);  
  28.         btStart.setOnClickListener(onClick);  
  29.         myHandler = new MyHandler();  
  30.   
  31.         WifiManager manager = (WifiManager) this  
  32.                 .getSystemService(Context.WIFI_SERVICE);  
  33.         lock= manager.createMulticastLock("myUDP");  
  34. //      lock.acquire();  
  35.           
  36.         client = new UDPThread("10.21.56.226"7000,"login:xuan,password:{888}"new MessageListener() {  
  37.   
  38.             @Override  
  39.             public void message(String msg) {  
  40.                 // TODO Auto-generated method stub  
  41.                 // tvMessage.append(msg);  
  42.                 Bundle bundle = new Bundle();  
  43.                 bundle.putString("input", msg);  
  44.                 Message isMessage = new Message();  
  45.                 isMessage.setData(bundle);  
  46.                 myHandler.sendMessage(isMessage);  
  47.             }  
  48.         });  
  49.         client.lock = this.lock;  
  50.         client.start();  
  51.   
  52.     }  
  53.   
  54.     OnClickListener onClick = new OnClickListener() {  
  55.         public void onClick(android.view.View v) {  
  56.             switch(v.getId()){  
  57.             case R.id.tvSend:  
  58.                 String message = etMessage.getText().toString();  
  59.                 Log.v("发送消息", message);  
  60.                 client.sendMessage(message);  
  61.                 break;  
  62.             case R.id.btClose:  
  63.                 client.close();  
  64.                 break;  
  65. //          case R.id.btStart:  
  66. //              client.start();  
  67. //              break;  
  68.             }  
  69.               
  70.         };  
  71.     };  
  72.   
  73.     private class MyHandler extends Handler {  
  74.         @Override  
  75.         public void handleMessage(Message msg) {  
  76.             // TODO Auto-generated method stub  
  77.             Log.v("处理收到的消息""  ");  
  78.             tvMessage.append(msg.getData().getString("input"));  
  79.         }  
  80.     }  
  81.   
  82.     @Override  
  83.     public void finish() {  
  84.         // TODO Auto-generated method stub  
  85.         super.finish();  
  86.           
  87.     }  
  88. }  
xml布局
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context="com.example.chatclient.MainActivity" >  
  10.   
  11.   
  12.     <ScrollView  
  13.         android:id="@+id/svMessage"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="100dp" >  
  16.   
  17.         <TextView  
  18.             android:id="@+id/tvMessage"  
  19.             android:layout_width="wrap_content"  
  20.             android:layout_height="wrap_content"  
  21.             android:text="消息内容:\n" />  
  22.     </ScrollView>  
  23.   
  24.     <EditText  
  25.         android:id="@+id/etMessage"  
  26.         android:layout_width="100dp"  
  27.         android:layout_height="wrap_content"  
  28.         android:layout_below="@+id/svMessage" />  
  29.   
  30.     <Button  
  31.         android:id="@+id/tvSend"  
  32.         android:layout_width="wrap_content"  
  33.         android:layout_height="wrap_content"  
  34.         android:layout_below="@+id/svMessage"  
  35.         android:layout_marginLeft="10dp"  
  36.         android:layout_toRightOf="@+id/etMessage"  
  37.         android:text="发送消息"  
  38.         android:textSize="25sp" />  
  39.     <Button   
  40.     android:id="@+id/btClose"  
  41.         android:layout_width="wrap_content"  
  42.         android:layout_height="wrap_content"  
  43.         android:layout_below="@+id/etMessage"  
  44.         android:layout_marginLeft="10dp"  
  45.         android:text="关闭连接"  
  46.         android:textSize="25sp"  
  47.         />  
  48.     <Button   
  49.     android:id="@+id/btStart"  
  50.         android:layout_width="wrap_content"  
  51.         android:layout_height="wrap_content"  
  52.         android:layout_below="@+id/btClose"  
  53.         android:layout_marginLeft="10dp"  
  54.         android:text="打开连接"  
  55.         android:textSize="25sp"  
  56.         />  
  57.       
  58. </RelativeLayout>  
android端的代码就是这样子的~

接下来把服务端的简单代码也贴上去,UDP服务端和客户端基本没啥使用上的区别,主要是接收数据,并且转发数据给其他人(包括自己,这样就确定自己真的发送出去了),服务端代码非常简单,只是为了测试Android端代码。如有不足,还望赐教~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值