Android基于Socket的网络通信

本文详细介绍Java Socket编程的基础知识,包括ServerSocket与Socket的工作原理及应用案例。从简单的文本通信到利用NIO与mina框架实现高性能服务器,再到Android客户端的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Socket用于在应用程序向网络发出请求或者应答网络请求。ServerSocket用于服务器端,Socket用在建立网络连接时。若连接成功,应用程序两段都会产生一个Socket实例,操作这个实例完成会话。对于一个网络连接,Socket是平等的,不会因为服务器端或在客户端而产生不同级别。Socket基于TCP链接,数据传输有保障,较适用于建立长时间链接。通常Socket编程应用于即时通讯。


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

Socket服务器搭建

public class MyServerSocket {

   public static void main(String[] args) {
      
      new ServerListener().start();

   }

}

public class ServerListener extends Thread {

   @Override
   public void run() {
      //1-65535
      try {
         ServerSocket serverSocket = new ServerSocket(55555);
         while (true) {
            //accept阻塞主线程 使用新线程建立连接
            Socket socket = serverSocket.accept();

            JOptionPane.showMessageDialog(null, "有客户端链接到了本机的12345端口");
            //将socket传递给新的线程
            ChatSocket cs = new ChatSocket(socket);
            cs.start();
            ChatManager.getChatManager().add(cs);
         }
         
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
      
}

public class ChatSocket extends Thread {

   Socket socket;

   public ChatSocket(Socket s) {
      this.socket = s;
   }
   //广播消息	
   public void out(String out) {
      try {
         socket.getOutputStream().write((out+"\n").getBytes("UTF-8"));
      } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   @Override
   public void run() {
      //读取接收的消息
      try {
         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
         String line = null;
         while ((line = br.readLine()) != null) {
            System.out.println(line);
            ChatManager.getChatManager().publish(this, line);
         }
         br.close();
      } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

import java.util.Vector;

public class ChatManager {

   //聊天服务器只能有一个manager 故该类必须单例化
   private ChatManager() {}
   private static final ChatManager cm = new ChatManager();
   public static ChatManager getChatManager() {
      return cm;
   }
      
   Vector<ChatSocket> vector = new Vector<>();
   
   public void add(ChatSocket cs) {
      vector.add(cs);
   }
   
   public void publish(ChatSocket cs,String out) {
      for (int i = 0; i < vector.size(); i++) {
         ChatSocket chatSocket = vector.get(i);
         if (!cs.equals(chatSocket)) {
            chatSocket.out(out);
         }
      }
   }
}

搭建完成后可通过cmd telnet命令测试telnet localhost 12345


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

Java AIO ServerSocket

 
public class Main {
    public static void main(String[] args){

        try {
            AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
            server.bind(new InetSocketAddress(8000));
            while (true){
                /*server.accept(server, new CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel>() {
                    @Override
                    public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel attachment) {

                    }

                    @Override
                    public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {

                    }
                });*/


                AsynchronousSocketChannel socketChannel = server.accept().get();
                new SocketHandler(socketChannel);
            }
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

public class SocketHandler {

    ByteBuffer buffer = ByteBuffer.allocate(1024);
    public SocketHandler(AsynchronousSocketChannel channel) {

        //服务器监听得到的数据  发布数据可用channel.write
        channel.read(buffer, channel, new CompletionHandler<Integer, AsynchronousSocketChannel>() {
            @Override
            public void completed(Integer result, AsynchronousSocketChannel attachment) {
                buffer.flip();
                try {

                    String msg = new String(buffer.array(),0,buffer.remaining(),"UTF-8");
                    System.out.println(msg);
                    if (msg.trim().equals("quit")){
                        attachment.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                buffer.clear();
                if (result != -1) {
                    attachment.read(buffer,attachment,this);
                }else {
                    System.out.println("连接已断开");
                }
            }

            @Override
            public void failed(Throwable exc, AsynchronousSocketChannel attachment) {
                System.out.println("读取失败");
            }
        });

    }
}

同样用telnet测试


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

mina框架,基于NIO

进入mina官网:mina.apache.org,下载mina Binaries库,如需查看源代码一并下载Source。新建IEAD项目,新建libs目录,将mina-***-bin.zip中dist和lib的jar文件全部拷贝到项目libs中,然后右键Add as Library,有兴趣可以查看mina-example的示例代码。

简单用法如下:

public class Main {

    public static void main(String[] args){

        NioSocketAcceptor acceptor = new NioSocketAcceptor();

//        acceptor.getFilterChain().addLast("textLineCodec",new ProtocolCodecFilter(new TextLineCodecFactory()));//添加滤镜 API中的滤镜   -->将数据分成一行一行
        acceptor.getFilterChain().addLast("StringFilter",new StringFilter());//自定义字符串滤镜

        acceptor.setHandler(new SocketHandler());
        try {
            acceptor.bind(new InetSocketAddress(55555));
            System.out.println("Server started at port 55555");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//自定义的ProtocolCodecFilter
public class StringFilter extends IoFilterAdapter {

    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {

        IoBuffer buffer = (IoBuffer) message;
        String str = new String(buffer.array(),"UTF-8").trim();

        super.messageReceived(nextFilter, session, str);
//        super.messageReceived(nextFilter, session, message);
    }
}

public class SocketHandler extends IoHandlerAdapter{

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        super.sessionCreated(session);

        System.out.println("create");
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        super.messageReceived(session, message);

        /*
        //无滤镜  --------------telnet 要用 send 命令输入消息!!!!!!!!!!!!
        IoBuffer buffer = (IoBuffer) message;
        String str = new String(buffer.array(),"UTF-8");
        System.out.println(str.trim());*/
        //加滤镜之后数据变成一行一行的  ----------telnet 可直接输入消息!!!!!!!!!!
        //自定义字符串滤镜也是用下面方法   ----------telnet 要用 send 命令输入消息!!!!!!!!!!!
        String line = (String) message;
        System.out.println(line);
        if (line.equals("quit")){
            session.close(true);
        }
    }
}
若要实现聊天功能,在Handler记录每个session的创建与销毁,接收到消息时还需广播给这些session:

    private List<IoSession> allSessions = new ArrayList<>();

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        super.sessionCreated(session);

        allSessions.add(session);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        super.sessionClosed(session);

        allSessions.remove(session);
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        super.messageReceived(session, message);

//        for (IoSession ioSession:allSessions){
//            ioSession.write(message);
//        }

        allSessions.stream().filter(ioSession -> !ioSession.equals(session)).forEach(ioSession -> ioSession.write(message));

    }

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

Android客户端

Socket链接最好写在Service里面,这里为方便演示直接放在Activity里。



 

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText ip, editText;
    private TextView text;
    private Button btnConnect, btnSend;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ip = (EditText) findViewById(R.id.etIP);
        editText = (EditText) findViewById(R.id.etSend);
        text = (TextView) findViewById(R.id.tvChat);
        btnConnect = (Button) findViewById(R.id.btnConnect);
        btnSend = (Button) findViewById(R.id.btnSend);

        btnConnect.setOnClickListener(this);
        btnSend.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnConnect:
                connect();
                break;
            case R.id.btnSend:
                send();
                break;
        }
    }

    //TODO-----------------------------------------------------
    Socket socket = null;
    BufferedWriter writer = null;
    BufferedReader reader = null;

    public void connect() {

        //手机连接本地的地址 真机就是连接wifi的ip 虚拟机10.0.0.2或者其他  比如我的10.0.3.2
        final String dstName = ip.getText().toString();
        AsyncTask<Void, String, Void> read = new AsyncTask<Void, String, Void>() {
            @Override
            protected Void doInBackground(Void... params) {

                try {
                    socket = new Socket(dstName, 12345);
                    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    publishProgress("@success");
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        publishProgress(line);
                    }
                } catch (IOException e) {
                    Toast.makeText(MainActivity.this, "无法建立连接", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onProgressUpdate(String... values) {
                if (values[0].equals("@success")) {
                    Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
                }
                text.append("别人说:" + values[0] + "\n");
                super.onProgressUpdate(values);
            }
        };
        read.execute();

    }

    public void send() {

        try {
            text.append("我说:" + editText.getText().toString() + "\n");
            writer.write(editText.getText().toString() + "\n");
            writer.flush();
            editText.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}


































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值