安卓网络应用---Socket

Socket

 socket套接字,和java网络编程部分类似,通过socket可以实现客户端与服务器的链接(c/s),使用ServerSocket可以创建TCP服务器端,与客户端建立三次握手连接。

通过一个例子熟悉:

简单的c/s聊天室

服务器端

(使用MyEclipse编写的):
public static void main(String args[]){

    try {
        ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
        System.out.println("启动了服务器");

        while(true){
            Socket socket = serverSocket.accept();
            socketList.add(socket);
            System.out.println("成功连接客户端");
            //为每一个客户端socket单独开启一个线程通信
            new Thread(new MyServerThread(socket)).start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } 

}

主要通过 new ServerSocket(port)启动服务器Socket,再调用accepet(),接收来自客户端的链接请求,因为是聊天室,一个客户端发送信息要同时让其他客户端收到,所以给每个客户端socket开启一个线程用于发送和读取消息。

客户端自定义线程类,用于处理服务器和客户端的交互数据:

@Override
    public void run() {
        String content = null;
        //采用循环不断的从Socket中读取客户端发送过来的数据
        while ((content = readFromClient()) != null) {
            for (Socket socket : MyServer.socketList) {
                //遍历每个Socket,把读到的内容向每一个Socket发送一遍
                try {
                    OutputStream outputStream =    socket.getOutputStream();
                     outputStream.write((content+"\n").getBytes("utf-8"));
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

读数据的方法:

    /* * 从客户端读取数据到服务器 */
    private String readFromClient() {
        String content = null;
        try {
            content = bufferedReader.readLine();
            return content;
        } catch (IOException e) {
            e.printStackTrace();
            // 捕捉到异常,说明该Socket对应的客户端已关闭
            MyServer.socketList.remove(socket);
        }
        return null;
    }

然后运行,服务器端就准备好了 : )

客户端(用AndroidStudio编写):

客户端界面:简单聊天界面,一个EditText,一个Button发送信息,一个TextView显示从服务器读取的信息.

重点在于如何与服务器进行连接和从子线程修改UI线程(主线程)组件。

关键代码(MainActivity):

public static String URL_PATH = "192.168.2.1";  //访问服务器地址
    public static int SERVER_PORT = 50000;  //服务器端口号
    public static int TIMEOUT = 5000; //超时限定

    public static final int MESSAGE_APPENDTEXT = 0x111;
    public static final int MESSAGE_EDITTEXT = 0x111;
private Handler myHandler = new Handler () {
        @Override
        public void handleMessage (Message msg) {
            super.handleMessage (msg);
            if (msg.what == MESSAGE_APPENDTEXT) {
                textView.append (msg.obj.toString () + "\n");
            } else if (msg.what == 0x222) {
                Toast.makeText (MainActivity.this, "连接服务器失败", Toast.LENGTH_SHORT).show ();
            }
        }
    };
private void initViews () {
        textView = (TextView) findViewById (R.id.textView);
        button = (Button) findViewById (R.id.button);
        editText = (EditText) findViewById (R.id.editText);
        button.setOnClickListener (new View.OnClickListener () {
            @Override
            public void onClick (View v) {
                Message message = new Message ();
                message.what = MainActivity.MESSAGE_EDITTEXT;
                message.obj = editText.getText ().toString ();
                myClientThread.revHandler.sendMessage (message);
                editText.setText ("");
            }
        });
    }
@Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        initViews ();

        myClientThread = new MyClientThread (myHandler);
        new Thread (myClientThread).start ();

    }

客户端子线程的实现类MyClientThread :

public class MyClientThread implements Runnable{

    private Handler handler; //向ui发送消息的Handler对象
    public Handler revHandler; //接受ui发来的消息的Handler对象

    private BufferedReader bufferedReader;
    private OutputStream outputStream;

    public MyClientThread(Handler handler){
        this.handler = handler;
    }

    @Override
    public void run () {
        try {
        //建立Socket连接服务器
            Socket socket = new Socket (MainActivity.URL_PATH,MainActivity.SERVER_PORT);
            socket.setSoTimeout (MainActivity.TIMEOUT);
            bufferedReader = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
            outputStream = socket.getOutputStream ();
            //启动一条子线程来读取服务器的数据
            new Thread (new Runnable () {
                 String content;
                @Override
                public void run () {
                    try {
                        while((content = bufferedReader.readLine ())!=null){
                            Message message = new Message ();
                            message.what = MainActivity.MESSAGE_APPENDTEXT;
                            message.obj = content;
                            handler.sendMessage(message);
                        }
                    } catch (IOException e) {
                        e.printStackTrace ();
                    }
                }
            }).start ();

            Looper.prepare ();
            revHandler = new Handler (){
                @Override
                public void handleMessage (Message msg) {
                    //接受用户输入的数据
                    if (msg.what==MainActivity.MESSAGE_EDITTEXT){
                        try {
                            outputStream.write ((msg.obj.toString ()+"\r\n").getBytes ("utf-8"));
                        } catch (IOException e) {
                            e.printStackTrace ();
                        }
                    }
                }
            };
            Looper.loop ();

        }catch (SocketTimeoutException e){
            Log.e ("TimeOut", "连接服务器超时");
        } catch (SocketException e) {
            e.printStackTrace ();
        } catch (UnknownHostException e) {
            e.printStackTrace ();
        } catch (IOException e) {
            e.printStackTrace ();
        }

    }
}

为什么要在子线程中还开一条子线程用于读取服务器数据呢?我想是因为怕子线程发送数据给服务器的同时,其他客户端向服务器也发送了数据,对于我自己这个客户端就要从服务器接收数据(就是聊天室别人发信息我同时也要从服务器接收到信息),收发同时为了避免线程拥塞,所以在子线程中再开一个子线程单独用于发送数据给服务器。

注意的地方:

网络通信在安卓中一般放在子线程中进行,主线程一般用于UI操作。
安卓网络通信加权限:
<uses-permission android:name="android.permission.INTERNET"/>

截图:

启动服务器:
安卓网络应用---Socket_第1张图片

客户端:

安卓网络应用---Socket_第2张图片

完结撒花,如有不足,望批评指正。

附:源码下载-

Rose.Chan—Socket简易聊天室

你可能感兴趣的:(java,socket,安卓,网络编程,安卓网)