Android客户端与本地服务器Socket通信

Android客户端与本地服务器Socket通信

Socket服务器运行结果图:smile:

一.客户端和服务器端的选择:

  • 客户端是我们手机端,关于服务器端,只要安装了JDK,自然就拥有通讯的功能,我们只需要在Eclipse或者MyEclipse中写好文章中服务器端的代码,运行起来即可,用accept()方法启动服务器端,等待客户端的连接,在未连接的情况下,服务器端处于堵塞的状态。

二.客户端注意事项

  • andriod客户端添加网络访问权限
    <uses-permission android:name="android.permission.INTERNET" />

  • 对Socket的操作放在非UI线程内进行

  • 要使用正确的IP地址和端口号端口号的范围是0~65535,1024一下的端口被系统分给了一些服务,在cmd窗口执行netstat -ano命令可以看到所有端口的使用情况

  • 真机进行调试(1、连接上手机,手机开启adb。步骤:设置> 应用程序> 开发>选择USB调试;usb选项有些不可见,具体百度),指定Server的IP地址,此地址为局域网地址,如果是使用WIFI上网,则为PC机的WIFI IP。上图中连接的第二个就是示例

三.Socket通信

  • 利用ip地址+端口号唯一标示网络中的一个进程,能够唯一标示网络中的进程后,它们就可以利用socket进行通信。

  • socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用,实现进程在网络中通信。

  • socket是“打开—读/写—关闭”模式的实现(只能读取对方放在流中的数据),以使用TCP协议通讯的socket为例,其交互流程大概是这样子的

  • Socket有两种主要的操作方式:面向连接的和无连接的,即TCP和UDP。
      面向连接的Socket操作就像一部电话,Socket必须在发送数据之前与目的地的Socket取得连接,一旦连接建立了,Socket就可以使用一个流接口进行打开、读写以及关闭操作。并且,所有发送的数据在另一端都会以相同的顺序被接收。

  • 无连接的Socket操作就像一个邮件投递,每一个数据报都是一个独立的单元,它包含了这次投递的所有信息(目的地址和要发送的内容)。在这个模式下的Socket不需要连接目的地Socket,它只是简单的投出数据报。

四.TCP连接与HTTP连接与Socket连接的区别

  • TCP连接与HTTP连接的区别

    HTTP是基于TCP的,客户端往服务端发送一个HTTP请求时第一步就是要建立与服务端的TCP连接。

  • TCP连接与Socket连接的区别:

socket层只是在TCP/UDP传输层上做的一个抽象接口层,基于TCP协议的socket连接同样需要通过三次握手建立连接,是可靠的;基于UDP协议的socket连接不需要建立连接的过程,不过对方能不能收到都会发送过去,是不可靠的,大多数的即时通讯IM都是后者。

  • HTTP连接与Socket连接的区别

HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。

HTTP连接服务端无法主动发消息。决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。

  • 什么时候该用HTTP,什么时候该用socket

用HTTP的情况:双方不需要时刻保持连接在线,比如客户端资源的获取、文件上传等。

用Socket的情况:大部分即时通讯应用(QQ、微信)、聊天室、苹果APNs等。

五.socket代码

客户端代码

public class MainActivity extends AppCompatActivity {
//IP地址和端口号
public static String IP_ADDRESS = "192.168.1.106";
public static int PORT = 2346;
//三个控件
EditText text = null;
Button connect = null;
TextView info = null;
//handler
Handler handler = null;
Socket soc = null;
DataOutputStream dos = null;
DataInputStream dis = null;
String messageRecv = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    text = (EditText) findViewById(R.id.editText);
    connect = (Button) findViewById(R.id.buttonConnection);

    info = (TextView) findViewById(R.id.info);
    connect.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new ConnectionThread(text.getText().toString()).start();
        }
    });
    handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle b = msg.getData();  //获取消息中的Bundle对象
            String str = b.getString("data");  //获取键为data的字符串的值
            info.append(str);
        }
    }; }


            //新建一个子线程,实现socket通信
    class ConnectionThread extends Thread {
    String message = null;

    public ConnectionThread(String msg) {
        message = msg;
    }

    @Override
    public void run() {
        if (soc == null) {
            try {
                //Log.d("socket","new socket");
                soc = new Socket(IP_ADDRESS, PORT);
                //获取socket的输入输出流
                dis = new DataInputStream(soc.getInputStream());
                dos = new DataOutputStream(soc.getOutputStream());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try {
            dos.writeUTF(message);
            dos.flush();
            messageRecv = dis.readUTF();//如果没有收到数据,会阻塞
            Message msg = new Message();
            Bundle b = new Bundle();
            b.putString("data", messageRecv);
            msg.setData(b);
            handler.sendMessage(msg);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
}

`
服务器端代码

public class Server {

ServerSocket serverSocket = null;
public final int port = 2346;

public Server(){

        //输出服务器的IP地址
        try {
            InetAddress addr = InetAddress.getLocalHost();
            System.out.println("local host:"+addr);
            serverSocket = new ServerSocket(port);
            System.out.println("0k");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

public void startService(){

    try {
        Socket socket = null;
        System.out.println("waiting...");
        //等待连接,每建立一个连接,就新建一个线程
        while(true){                
            socket = serverSocket.accept();//等待一个客户端的连接,在连接之前,此方法是阻塞的
            System.out.println("connect to"+socket.getInetAddress()+":"+socket.getLocalPort());
            new ConnectThread(socket).start();
        }

    } catch (IOException e) {
        // TODO Auto-generated catch block
        System.out.println("IOException");
        e.printStackTrace();
    }
}

//向客户端发送信息
class ConnectThread extends Thread{
    Socket socket = null;

    public ConnectThread(Socket socket){    
        super();
        this.socket = socket;
    }

    @Override
    public void run(){
        try {
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            while(true){
                String msgRecv = dis.readUTF();
                System.out.println("msg from client:"+msgRecv);
                dos.writeUTF("received:"+msgRecv);
                dos.flush();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
public static void main(String[] args) {
    // TODO Auto-generated method stub
    new Server().startService();
}

}

代码的逻辑

客户端 :

  1. 初始化控件,并绑定监听器,编写按钮的事件处理代码。

  2. 在事件处理代码中开启子线程,子线程中通过Sockt访问服务器。

  3. 利用异步消息处理机制,message对象将子线程的数据传回handle的处理方法更新UI。

    服务端

  4. serversocket对象监听等待,利用循环当有客户访问就开启子线程处理传消息回客户端。(模拟器和手机同时通过局域网访问)

最后的废话

  1. 搞计算机必须得有理论指导实践,否则只能像个没头苍蝇到处乱撞,我的计算机网络知识真的是一言难尽。

  2. 各大语言的官网是个好东西。丰富的资料和教程简直让人沉醉其中不能自拔。虽然比不上网络小说通俗易懂,但是引人入胜一点也不差。

  3. 不会的东西太多,用谷歌插件等工具列表,先解决主要的,平时有想法也可以记录。

  4. 用博客整理自己的知识,形成体系。看得再多不如编一遍。


PS. 集成了很多地方的知识点,官网,博主,就不一一记录原地址了。

2018-05-13 22:15:53 星期日

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页