android 通信之Socket
基于android的Socket通信
一、Socket简介:
1.1 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信。两者最大差异在于:
Http: 使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。
Socket: 在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求。
1.2 通俗理解:Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。
Socket是应用层与传输层的一个抽象,将复杂的TCP/IP协议隐藏在Socket接口之后,只对用户暴露简单的接口。
1.3 表示方法:socket=(IP地址:端口号)
1.4 主要类型(根据底层不同的协议):a.流套接字(SOCK_STREAM)基于Tcp传输;b.数据报套接字(SOCK_DGRAM)基于udp传输;
c.原始套接字(SOCK_RAW)原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。
因此,如果要访问其他协议发送的数据必须使用原始套接
1.5 基本通信模型如下图:
其中针对TCP socket通信通过,inputstream/outputstream进行流读取和写入。UDP经过datagram进行数据包的收发。
二、Socket在android中的应用。
2.1 服务器端首先声明一个ServerSocket对象并且指定端口号,然后调用Serversocket的accept()方法接收客户端的数据。
accept()方法在没有数据进行接收的处于堵塞状态。(Socket socket=serversocket.accept()),一旦接收到数据,
通过inputstream读取接收的数据。
客户端创建一个Socket对象,指定服务器端的ip地址和端口号(Socket socket=newSocket("172.168.10.108",8080);),
通过inputstream读取数据,获取服务器发出的数据(OutputStream outputstream=socket.getOutputStream()),
最后将要发送的数据写入到outputstream即可进行TCP协议的socket数据传输。
2.2 通过如下demo 模拟socket在客户端的使用:
2.2.1 在manifest进行权限声明,此处用的路由局域网。
<uses-permission android:name="android.permission.INTERNET" />
2.2.2 使用TCP通信,界面布局做一简单布置,不做过多介绍,界面只有有一button,来启动客户端和服务器两个线程,客户端写入的内容,将在服务端进行解析,后handler发送 在ui的TextView中显示。UI如下:
public class MainActivity<countClient> extends AppCompatActivity {
TextView textView;
EditText editText;
Button bt;
String tag = this.toString();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
textView = (TextView) findViewById(R.id.textV);
bt.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
new ServiceThread().start();//启动服务器
new ClientThread().start();//启动客户端
}
}
);
}
public Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 100:
if(msg.obj == null) return;
Log.d(tag,"service receive..msg:" + msg.obj.toString());
textView.append(msg.obj.toString());
break;
}
}
};
2.2.3.客户端代码如下:
public int countClient = 0; class ClientThread extends Thread { Socket mSocket = null; @Override public void run() { try { Log.d(tag,"ClientThread"); mSocket = new Socket(/*"172.16.99.105"*/InetAddress.getLocalHost(), 9001);//链接服务器地址,端口9001.在使用此ip时可以先进行ping Log.d(tag,"InetAddress.getLocalHost:" + InetAddress.getLocalHost()); OutputStream outputStream = mSocket.getOutputStream(); PrintWriter pw = new PrintWriter(outputStream); countClient ++; pw.write("客户端给服务器端发送的数据"+countClient); pw.flush(); //关闭输出流 mSocket.shutdownOutput(); pw.close(); mSocket.close(); } catch (IOException e) { e.printStackTrace(); Log.d(tag,"Client IOExcept..e: " + e); } } }
2.2.4.服务端代码如下:
class ServiceThread extends Thread { ServerSocket mServiceSocket = null; Socket mSocket = null; TextView textView; @Override public void run() { try { Log.d(tag,"serviceThread"); mServiceSocket = new ServerSocket(9001);//统一端口 mSocket = mServiceSocket.accept(); InputStream inputStream = mSocket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String line; StringBuilder sb = new StringBuilder(); try { while ((line = br.readLine()) != null) { sb.append(line); sb.append("\n"); } br.close(); } catch (IOException e) { e.printStackTrace(); } Message msg = new Message(); msg.what =100; msg.obj = sb; mHandler.sendMessage(msg);
mSocket.close();
} catch (IOException e) { e.printStackTrace(); } } }
三、总结:
使用UDP方式通信和TCP发送接受大相径庭,相同都是进行ip端口设置,只是TCP使用的是流的方式发送,UDP是以包的形式发送。
完整demo可以下载:https://download.csdn.net/download/code_code_88/25312072