基于安卓4.4的socket通信——文字聊天

时间:2022-08-13 22:42:38

       学习了3个月安卓了,今天开始写点东西。

      这个安卓的聊天demo,还是分为客户端、服务器两大部分,先来看看客户端:

      界面代码如下:

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		init();
		//打开应用就默认连接
		cHandler.sendEmptyMessage(0x01);
	}

	
	private void init() {
		cButtonSend = (Button) findViewById(R.id.btn);
		cName = (EditText) findViewById(R.id.yhm);
		cToName = (EditText) findViewById(R.id.jsm);
		cEditTextContent = (EditText) findViewById(R.id.et);
		
		cList = (ListView) findViewById(R.id.listview);
		
		mAdapter = new ChatMsgViewAdapter(this, mDataArrays);
		cList.setAdapter(mAdapter);
		cButtonSend.setOnClickListener(new OnClickListener() {
			
			
			@Override
			public void onClick(View v) {
				if( cName.getText().toString().equals("") || cName.getText().toString()==null || cToName.getText().toString().equals("") || 
						cToName.getText().toString()==null || cEditTextContent.getText().toString().equals("") || cEditTextContent.getText().toString()==null){
					
					new AlertDialog.Builder(
							MainActivity.this)
							.setTitle("")
							.setMessage("请填写完整!")
							.setPositiveButton("确定", null).show();
				}else{
					//发送信息展现
					ChatMsgEntity entity = new ChatMsgEntity();
					entity.setDate(getDate());
					entity.setName(cName.getText().toString());
					entity.setMsgType(false);
					entity.setText(cEditTextContent.getText().toString());
					
					mDataArrays.add(entity);
					mAdapter.notifyDataSetChanged();
					cList.setSelection(cList.getCount() - 1);
					
					cHandler.sendEmptyMessage(0x01);
					
					//清楚输入框内容
					cEditTextContent.setText("");
				}
			}
		});
		

	}
     socket相关代码:

	Handler cHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch (msg.what) {
			case 0x01:
				cThread = new Thread() {
					@Override
					public void run() {
						super.run();
						DataInputStream dis = null;
						DataOutputStream dos = null;
						try {
							
							// 阻塞函数,正常连接后才会向下继续执行
							cSocket = new Socket(ADDRESS, PORT);
							dis = new DataInputStream(cSocket.getInputStream());
							dos = new DataOutputStream(cSocket.getOutputStream());
							
							if(mDataArrays.isEmpty()){//刚打开应用,只是建立连接
							}else{
							// 向服务器写数据
							ChatMsgEntity e = new ChatMsgEntity();
							e = mDataArrays.get(mDataArrays.size()-1);
							
							dos.writeUTF(e.getName());
							dos.writeUTF(cToName.getText().toString());
							dos.writeUTF(e.getText().toString());
							
							// 读取服务器发来的数据
							//cContent += dis.readUTF();
							recive1 = dis.readUTF();
							recive2 = dis.readUTF();
							if(recive1.equals("错误*001\n我不在线")){
								//对方不在线,发送失败
								cHandler.sendEmptyMessage(0x03);
							}else{
								//接收信息展现
								cHandler.sendEmptyMessage(0x04);
							}
							

							}
							
							
						} catch (UnknownHostException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						} finally {
							try {
								if (dis == null) {
									dis.close();
								}
								if (dos == null) {
									dos.close();
								}
							} catch (IOException e) {
								e.printStackTrace();
							}
//							cHandler.sendEmptyMessage(0x02);
						}
					}

				};
				cThread.start();
				break;
			case 0x02:
//				cTextViewContent.setText(cContent);
				break;
			case 0x03://对方不在线,发送失败
				recive(recive2, recive1);
				break;
			case 0x04://接收信息展现
				recive(recive1, recive2);
				break;

			default:
				break;
			}
		}

	};

     下面是接收服务端返回的消息(包括他人发送给你,和你发送消息,但是对方不在线返回的消息)

     其中关键是修改界面必须要在主线程中完成:mAdapter.notifyDataSetChanged();

	public void recive(String a, String b){
		ChatMsgEntity e = new ChatMsgEntity();
		e.setName(a);
		e.setMsgType(true);
		e.setText(b);
		e.setDate(getDate());
		mDataArrays.add(e);
		
		mAdapter.notifyDataSetChanged();
		cList.setSelection(cList.getCount() - 1);
	}

     最后不要忘了配置相关权限,

 <!-- 添加联网权限 -->
    <uses-permission android:name="android.permission.INTERNET" />


     接下去看服务端代码:

     

public class MultiThreadServer {
    private int port=8888;
    private ServerSocket serverSocket;
    private static ExecutorService executorService;//线程池
    private final int POOL_SIZE=10;//单个CPU线程池大小
    static HashMap<String, Socket> map=new HashMap<String, Socket>();//保存链接
    
    public MultiThreadServer() throws IOException{
        serverSocket=new ServerSocket(port);
        //Runtime的availableProcessor()方法返回当前系统的CPU数目.
        setExecutorService(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE));
        System.out.println("服务器启动");
    }
    
    public void service(){
        while(true){
            Socket socket=null;
            try {
                //接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接
                socket=serverSocket.accept();
                getExecutorService().execute(new Handler(socket));
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) throws IOException {
        new MultiThreadServer().service();
    }

	public static ExecutorService getExecutorService() {
		return executorService;
	}

	public void setExecutorService(ExecutorService executorService) {
		MultiThreadServer.executorService = executorService;
	}

}

class Handler implements Runnable{
    private Socket socket;
    public Handler(Socket socket){
        this.socket=socket;
    }
    
    public void run(){
    	
    	DataInputStream dis = null;
		DataOutputStream dos = null;
		try {
				while (true) {
				System.out.println("正在等待客户连接...");
				// 这里处于等待状态,如果没有客户端连接,程序不会向下执行
				dis = new DataInputStream(socket.getInputStream());
				dos = new DataOutputStream(socket.getOutputStream());
				// 读取数据
				String fp = dis.readUTF();
				String tp = dis.readUTF();
				
				String clientStr = dis.readUTF();
				
				System.out.println("---客户端已成功连接---");
				
				MultiThreadServer.map.put(fp, socket);
				// 得到客户端的IP
				System.out.println("客户端的IP=" + socket.getInetAddress());
				// 得到客户端的端口号
				System.out.println("客户端的端口号=" + socket.getPort());
				// 得到本地端口号
				System.out.println("本地服务器端口号=" + socket.getLocalPort());
				System.out.println("信息:" + fp +"对"+ tp +"说:"+ clientStr);
				System.out.println("---------------------------------");
				
				//判断接收方 是否在线
				if(MultiThreadServer.map.containsKey(tp)){
					Socket socket1=MultiThreadServer.map.get(tp);
					DataOutputStream out=new DataOutputStream(socket1.getOutputStream());
					out.writeUTF(fp);
					out.writeUTF(clientStr);
					out.flush();
				}else{
					// 写出数据
					dos.writeUTF("错误*001\n我不在线");
					dos.writeUTF(tp);
				}
				
				//消息转发不能新建一个socket,原来端口被占用 会报错
//				MultiThreadServer.getExecutorService().execute(new Handler1(socket.getInetAddress().toString(),socket.getPort(),clientStr,fp));
			}
		}catch (EOFException e) {
			 System.out.println("这是合法的,客户端连接已断开");
		}catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (dis != null) {
					dis.close();
				}
				if (dos != null) {
					dos.close();
				}
//				 if(socket!=null){
//					 socket.close();
//				 }
                  
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

    }
}

     下面看一下运行效果:

基于安卓4.4的socket通信——文字聊天

    如上图,是自己发送消息给自己,下图为发送给别人。

基于安卓4.4的socket通信——文字聊天

     安卓文本聊天的至此完结,虽然还有很多不足,以后有机会再改了。