在学习Socket之前,我们需要掌握一些知识,如java多线程,Handler等.

Java多线程

https://blog.csdn.net/qq_40318498/article/details/84726026

C#Socket通信

https://blog.csdn.net/qq_40318498/article/details/90384688

Android Handler消息处理

https://blog.csdn.net/qq_40318498/article/details/89897690




源码已上传到github上

https://github.com/Githubforusc2018/AndroidSocket




使用技术

1.Handler
2.多线程
3.网络编程

Android登录界面截图

在这里插入图片描述

Android客户端界面截图

在这里插入图片描述

Android服务端界面截图

在这里插入图片描述




Client客户端核心代码

	//连接服务器,返回的是一个Socket对象的连接来保持与服务器的通信.
	int port = Integer.parseInt(clientPort.getText().toString());
    mysocket = new Socket(clientIp.getText().toString(),port); //连成功了,服务器一直显示数据.
    //一个子线程,循环读取消息.
    while(true){
	    InputStream is = mysocket.getInputStream(); //192.168.43.224手机的wifi ip 地址.
	    byte[] buffer = new byte[1024*1024];
	    int len = is.read(buffer);	//获取输入流,读取从服务端发送过来的消息.
	    String result = new String(buffer, 0, len);
	    /*  第一次读到的是Ip地址,必须保存.*/
	    if (mycount++==1){
	        myIp = result;	//这里是与C#服务端通信的需求,我是检测是否正常连接用的.
	    }
	    Message message = new Message();	
	    message.what = 1;   //标识符为1,表明显示在自己的消息框
	    Bundle bundle = new Bundle();
	    bundle.putString("msg", result);	//将读取到的信息传入handler中处理.
	    message.setData(bundle);
	    handler.sendMessage(message);
	}
	//发送消息,这里直接使用mysocket.getOutputStream()也可以.
	DataOutputStream writer = new DataOutputStream(mysocket.getOutputStream());
    writer.write(clientMessage.getText().toString().getBytes());	//发送消息
    //发送,我也要写入handler中.
    Message message = new Message();
    message.what = 1;   //标识符为1,表明显示在自己的消息框
    Bundle bundle = new Bundle();
    bundle.putString("msg", myIp+" : "+clientMessage.getText().toString());  //ip + 说明
    message.setData(bundle);
    handler.sendMessage(message);
    //Handler
    public Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1){
                Bundle data = msg.getData();
                sb.append(data.getString("msg"));	//StringBuffer sb = new StringBuffer();这里直接不用这个也可以.
                sb.append("\n");
                serverMessageText.setText(sb.toString());
            }
        }
    };

Server服务端端核心代码

	//设置一个端口,监听客户端的连接,监听手机服务端50000端口.
	serverSocket = new ServerSocket(50000); //绑定sport
    clientSocket = serverSocket.accept();   //serverSocket是该服务器的,clientSocket返回客户端的ip和端口.
    //clientSocket.toString返回的是socket(192.168.1.107 + port)
    //userText.setText(clientSocket.toString());  报错???,使用handler处理成功.
    //读取消息,开启一个子线程,反复监听消息.
    while(true){
        //一开始客户端能给服务端发消息,服务端不能给客户端发消息,幸好解决了           
	    InputStream is = clientSocket.getInputStream();
	    byte[] buffer = new byte[1024*1024];
	    int len = is.read(buffer);
	    String result = new String(buffer, 0, len);	//读消息跟发送消息与客户端几乎一致.
	    Message message = new Message();
	    Bundle bundle = new Bundle();
	    bundle.putString("msg",result);
	    message.setData(bundle);
	    message.what = 1;   //标识符为1
	    handler.sendMessage(message);
	}
	//发送消息,也是需要开启一个线程.
	OutputStream writer = clientSocket.getOutputStream();
    writer.write(normalMessage.getText().toString().getBytes());   //发给1看看.
    String result = "发送成功";
    Message message = new Message();
    Bundle bundle = new Bundle();
    bundle.putString("msg",result);
    message.setData(bundle);
    //发送handler,更新ui
    message.what=1;
    handler.sendMessage(message);
    
    @SuppressLint("HandlerLeak")
    public Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1){
                Bundle data = msg.getData();
                sb.append(data.getString("msg"));
                sb.append("\n");
                normalText.setText(sb.toString());
            }
        }
    };

主界面中的图片切换动作使用handler处理和动画处理.
ListView客户端和ListView服务端在以上基础上,使用listview组件来显示消息,这里我对格式弄了一个处理,因此可能无法使用ListView客户端来与c#客户端进行数据交换,而只能使用Android与Android进行通信,可以解决该问题,如下.

	//Server服务端发送消息
	String result = userText.getText().toString() + "-" + classText.getText().toString() + "-" + ageText.getText().toString();
	//发送的是userText 内容 classText 内容 ageText内容 中间使用 - 来分割,这样容易把一串字节流按指定格式分割成我们想要的部分.
    writer.write(result.getBytes());
    //Client客户端
    Text = result.split("-");   //按分开.
    HashMap<String,Object> map = new HashMap<String, Object>();
    map.put("User",Text[0]);
    map.put("Class",Text[1]);
    map.put("Age",Text[2]);
    mylist.add(map);
    //我们发现,若C#服务端发送过来的消息不包含-因此Text[0] = result,Text[1],Text[2]抛出下标越界异常.
    //修改.
    int i=0;
    for(i=0;i<result.length();i++){
        if (result.charAt(i)=='-'){
            break;
        }
    }
    if (i==result.length()){
        //说明是C#发送过来的,对Text进行处理.
        Text[0] = result;
        Text[1] = "null";
        Text[2] = "null";
    }else{
        Text = result.split("-");   //按分开.
    }



Java split测试

在这里插入图片描述




一些总结:

1.服务端(假设是模拟机)可以向手机(服务端)发送请求连接,因此知道手机的ip地址能够正常连接,而手机客户端无法通过电脑的ip地址访问到模拟机(服务端),若要连接,需要知道模拟机的ip地址.

2.一个Message只能传给一个handler,若要使用handler处理多个任务,需要初始化多个Message.

3.可以使用bundle向handler中(可以是同一个活动)传递数据,在handler中使用Bundle bundle = msg.getData()来获取数据。

4.在退出活动的时候,需要关闭I/O流和socket连接.

5.使用5个write,怎么第一个输出有换行,明明程序中没有换行,最后写成一行可以解决该问题.
(若不写成一个write,可以通过trim()方法去掉多余的空格和换行)

6.Handler是Android提供的一个用来更新UI的机制(Android不允许在子线程更新UI),也是一个消息处理的机制

7.一些超时的任务处理,如网络下载等需要使用子线程来完成,因此默认情况下,主线程等待5s以上就会关闭该活动。




功能:

1.在C#Socket通信的基础上,增加Android Socket通信
2.能够让Android跟C#通信
3.能够让Android与Android进行通信.

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐