SocketDemo 类似聊天室

来源:互联网 发布:爱迪生电弧打火机 淘宝 编辑:程序博客网 时间:2024/06/06 04:49

服务端Java代码:

public class SocketDemo {private static final int SOCKET_PORT = 50000;public static ArrayList<Socket> socketList = new ArrayList<Socket>();public static void main(String[] args) {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(SOCKET_PORT);while (true) {Socket socket = serverSocket.accept();socketList.add(socket);new Thread(new SocketThread(socket)).start();}} catch (Exception e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}} catch (Exception e) {e.printStackTrace();}}}}class SocketThread implements Runnable {private Socket socket = null;private BufferedReader br = null;private BufferedWriter bw=null;public SocketThread(Socket socket) {this.socket = socket;}public void run() {try {while(true){String shared_content = "";StringBuffer buffer = new StringBuffer();if(br==null){br = new BufferedReader(new InputStreamReader(socket.getInputStream()));}String content;while (!"END".equals(content = br.readLine())) {buffer.append(content);}for (Socket mSocket : SocketDemo.socketList) {bw = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));shared_content = packageMessage(buffer.toString());bw.write(shared_content);bw.flush();}}} catch (Exception e) {e.printStackTrace();} finally {try {if (br != null) {br.close();}} catch (Exception e) {e.printStackTrace();}}}public String packageMessage(String msg) {String message = "";if (msg.startsWith("1")) {Date date = new Date();SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");String time = format.format(date);message = message + "user1 " + time + " :" + msg.substring(1)+"\r\n"+"END\r\n";}if (msg.startsWith("2")) {Date date = new Date();SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");String time = format.format(date);message = message + "user2 " + time + " :" + msg.substring(1)+"\r\n"+"END\r\n";}return message;}}

android客户端代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{    public static final int PORT=50000;    public static final String inetAddress="10.0.2.2";    private EditText mEditText;    private Button mButton1;    private Button mButton2;    private LinearLayout mLinearLayout1;    private LinearLayout mLinearLayout2;    private Socket socket1=null;    private Socket socket2=null;    private PrintWriter pw1=null;    private PrintWriter pw2=null;    private ClientThreadWriter clientThreadWriter1=null;    private ClientThreadWriter clientThreadWriter2=null;    private BufferedReader br1=null;    private BufferedReader br2=null;    private ClientThreadReader clientThreadReader1=null;    private ClientThreadReader clientThreadReader2=null;    private Handler handler=new Handler(){        public void handleMessage(Message msg){            switch(msg.what){                case 0:                    mEditText.setText("");                    break;                case 1:                    TextView mTextView1=new TextView(MainActivity.this);                    mTextView1.setText(msg.getData().getString("new_message"));                    mLinearLayout1.addView(mTextView1);                    break;                case 2:                    TextView mTextView2=new TextView(MainActivity.this);                    mTextView2.setText(msg.getData().getString("new_message"));                    mLinearLayout2.addView(mTextView2);                    break;            }        }    };    public void init(){        mEditText= (EditText) findViewById(R.id.edit_text);        mButton1= (Button) findViewById(R.id.button_1);        mButton2= (Button) findViewById(R.id.button_2);        mButton1.setOnClickListener(this);        mButton2.setOnClickListener(this);        mLinearLayout1= (LinearLayout) findViewById(R.id.record_1);        mLinearLayout2= (LinearLayout) findViewById(R.id.record_2);    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();    }    public void onClick(View view){        switch(view.getId()){            case R.id.button_1:                if(clientThreadWriter1==null){                    clientThreadWriter1=new ClientThreadWriter(1);                    clientThreadReader1=new ClientThreadReader(1);                    new Thread(clientThreadReader1).start();                }                new Thread(clientThreadWriter1).start();                break;            case R.id.button_2:                if(clientThreadWriter2==null){                    clientThreadWriter2=new ClientThreadWriter(2);                    clientThreadReader2=new ClientThreadReader(2);                    new Thread(clientThreadReader2).start();                }                new Thread(clientThreadWriter2).start();                break;        }    }    class ClientThreadWriter implements Runnable{        private int userId;        public ClientThreadWriter(int user){            userId=user;        }        public void run(){            try{                if(userId==1){                    if(socket1==null){                        //保证无论是user1还是user2都只持有一个socket,一个PrintWriter                        socket1=new Socket(inetAddress,PORT);                        pw1=new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));                        br1=new BufferedReader(new InputStreamReader(socket1.getInputStream()));                    }                    pw1.write(userId+mEditText.getText().toString()+"\r\n"+"END\r\n");                    pw1.flush();                    handler.sendEmptyMessage(0);                }                if(userId==2){                    if(socket2==null){                        //保证无论是user1还是user2都只持有一个socket,一个PrintWriter                        socket2=new Socket(inetAddress,PORT);                        pw2=new PrintWriter(new OutputStreamWriter(socket2.getOutputStream()));                        br2=new BufferedReader(new InputStreamReader(socket2.getInputStream()));                    }                    pw2.write(userId+mEditText.getText().toString()+"\r\n"+"END\r\n");                    pw2.flush();                    handler.sendEmptyMessage(0);                }                /*socket.shutdownOutput();*/            }catch(Exception e){                e.printStackTrace();            }        }    }    class ClientThreadReader implements Runnable{        private int userId;        public ClientThreadReader(int user){            userId=user;        }        public void run(){            try{                if(userId==1){                    while(true){                        if(socket1!=null){                            String content;                            StringBuffer buffer=new StringBuffer();Log.d("TAG123","reading");                            while(!"END".equals(content=br1.readLine())){                                buffer.append(content);                            }                            Message msg=Message.obtain();Log.d("TAG123",buffer.toString());                            Bundle bundle=new Bundle();                            bundle.putString("new_message",buffer.toString());                            msg.setData(bundle);                            msg.what=1;                            handler.sendMessage(msg);                        }                    }                }                if(userId==2){                    while(true){                        if(socket2!=null){                            String content;                            StringBuffer buffer=new StringBuffer();                            while(!"END".equals(content=br2.readLine())){                                buffer.append(content);                            }                            Message msg=Message.obtain();                            Bundle bundle=new Bundle();                            bundle.putString("new_message",buffer.toString());                            msg.setData(bundle);                            msg.what=2;                            handler.sendMessage(msg);                        }                    }                }            }catch(Exception e){                e.printStackTrace();            }        }    }}
运行效果:

编写过程中遇见的问题:
  BufferedReader的readLine方法,InputStream的read方法都是阻塞方法,服务端建立输入流读取客户端的PrintWriter输出流,当客户端未输入任何内容时,服务端的readLine并不会返回null,而是出于阻塞状态(阻塞线程)。当客户端输入内容后,若输入内容不能填满PrintWriter的缓冲区,且没有用flush刷新缓冲区,那么服务端readLine不会读取到数据,依旧会阻塞线程。当使用flush方法刷新缓冲区后,服务端while((content=br.readLine())!=null){.....}仍然会阻塞线程,通过在数据后面添加“\r\n”能够解除readLine的线程阻塞,返回读取到的String,但是下一轮循环继续读取流,流中没有数据,readLine继续阻塞线程。最后自定义了一个结束符“END\r\n”,且修改了while循环while (!"END".equals(content = br.readLine())){......},当读取到"END\r\n"时readLine返回“END”,使得while循环为false,退出循环。解决BufferedReader readLine阻塞线程问题。

Demo整体思路:

  客户端通过单击button开一个子线程去初始化socket,建立一个输出流,一个输入流,再开一个无限循环的子线程,不断读取来自服务端的数据。此后每次单击就仅单开一个线程向服务端输出数据即可。服务端通过ServerSocket.accept接收Socket,并开启一个无限循环的子线程去建立一个输入流,读取客户端的数据,再与服务端接收到的所有socket建立输出流,向客户端输出数据。

原创粉丝点击