ZERO、前言
有关Socket通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当,还望指教。
一、Socket通信简介
Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信。两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求。 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信。通过建立socket连接,可为通信双方的数据传输传提供通道。socket的主要特点有数据丢失率低,使用简单且易于移植。
1.1什么是Socket Socket
是一种抽象层,应用程序通过它来发送和接收数据,使用Socket可以将应用程序添加到网络中,与处于同一网络中的其他应用程序进行通信。简单来说,Socket提供了程序内部与外界通信的端口并为通信双方的提供了数据传输通道。
1.2Socket的分类
根据不同的的底层协议,Socket的实现是多样化的。本指南中只介绍TCP/IP协议族的内容,在这个协议族当中主要的Socket类型为流套接字(streamsocket)和数据报套接字(datagramsocket)。流套接字将TCP作为其端对端协议,提供了一个可信赖的字节流服务。数据报套接字使用UDP协议,提供数据打包发送服务。 下面,我们来认识一下这两种Socket类型的基本实现模型。
二、Socket 基本通信模型
三、Socket基本实现原理
3.1基于TCP协议的Socket
服务器端首先声明一个ServerSocket对象并且指定端口号,然后调用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。(Socketsocket=serversocket.accept()),一旦接收到数据,通过inputstream读取接收的数据。
客户端创建一个Socket对象,指定服务器端的ip地址和端口号(Socketsocket=newSocket("172.168.10.108",8080);),通过inputstream读取数据,获取服务器发出的数据(OutputStreamoutputstream=socket.getOutputStream()),最后将要发送的数据写入到outputstream即可进行TCP协议的socket数据传输。
3.2基于UDP协议的数据传输
服务器端首先创建一个DatagramSocket对象,并且指点监听的端口。接下来创建一个空的DatagramSocket对象用于接收数据(bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)),使用DatagramSocket的receive方法接收客户端发送的数据,receive()与serversocket的accepet()类似,在没有数据进行接收的处于堵塞状态。
客户端也创建个DatagramSocket对象,并且指点监听的端口。接下来创建一个InetAddress对象,这个对象类似与一个网络的发送地址(InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定义要发送的一个字符串,创建一个DatagramPacket对象,并制定要讲这个数据报包发送到网络的那个地址以及端口号,最后使用DatagramSocket的对象的send()发送数据。*(Stringstr="hello";bytedata[]=str.getByte();DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
代码如下:
客户端:
package com.example.socketdemo;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
public class ClientTCPSocket {
private Context context;
private Handler handler;
public ClientTCPSocket(Context context, Handler handler) {
this.context = context;
this.handler = handler;
}
public void client() {
Socket socket;
try {
// 创建一个Socket对象,并指定服务端的IP及端口号,这里服务端的IP就是手机的Ip
socket = new Socket(GetHostIp(), 1989);
// 从手机选择一个文件读取
InputStream inputStream = new FileInputStream("/mnt/sdcard/a.txt");
// 获取Socket的OutputStream对象用于发送数据。
OutputStream outputStream = socket.getOutputStream();
// 创建一个byte类型的buffer字节数组,用于存放读取的本地文件
byte buffer[] = new byte[4 * 1024];
int temp = 0;
while ((temp = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, temp);
}
InputStream socketStream = socket.getInputStream();
byte buf[] = new byte[1024];
int tem = 0;
// 从InputStream当中读取客户端所发送的数据 ,发送一个Handler用于更新界面
while ((tem = socketStream.read(buf)) != -1) {
Message msg = new Message();
msg.what = 1;
msg.obj = new String(buf, 0, tem, "UTF-8");
handler.sendMessage(msg);
}
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
// 获得手机的IP地址
public static String GetHostIp() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en
.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> ipAddr = intf.getInetAddresses(); ipAddr
.hasMoreElements();) {
InetAddress inetAddress = ipAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException ex) {
} catch (Exception e) {
}
return null;
}
}
服务端:
package com.example.socketdemo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
public class ServerTCPSocket {
private Context context;
private Handler handler;
public ServerTCPSocket(Context context, Handler handler) {
this.context = context;
this.handler = handler;
}
public void server() {
// 声明一个ServerSocket对象
ServerSocket serverStock = null;
try {
// 创建一个ServerSocket对象,并让这个Socket在1989端口监听
serverStock = new ServerSocket(1989);
// 调用ServerSocket的accept()方法,该方法是一个阻塞方法,接受客户端所发送的请求,
// 如果客户端没有发送数据,那么该线程就停滞不继续
Socket socket = serverStock.accept();
// 从Socket当中得到OutputStream对象,用于向客户端发送数据
String out = "服务器已收到";
byte buf[] = out.getBytes();
OutputStream outputStream = socket.getOutputStream();
outputStream.write(buf, 0, buf.length);
// 从Socket当中得到InputStream对象
InputStream inputStream = socket.getInputStream();
byte buffer[] = new byte[1024 * 4];
int temp = 0;
// 从InputStream当中读取客户端所发送的数据 ,发送一个Handler用于更新界面
while ((temp = inputStream.read(buffer)) != -1) {
Message msg = new Message();
msg.what = 0;
msg.obj = new String(buffer, 0, temp, "gb2312");
handler.sendMessage(msg);
}
serverStock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
主文件:
package com.example.socketdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button sendBtn, receiveBtn;
private TextView receiveTxt, sendTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendBtn = (Button) findViewById(R.id.btn_send);
receiveBtn = (Button) findViewById(R.id.btn_receive);
sendTxt = (TextView) findViewById(R.id.txt_send);
receiveTxt = (TextView) findViewById(R.id.txt_receive);
sendBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
new Thread() {
public void run() {
ClientTCPSocket socket = new ClientTCPSocket(MainActivity.this, handler);
socket.client();
};
}.start();
}
});
receiveBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
public void run() {
ServerTCPSocket socket = new ServerTCPSocket(MainActivity.this, handler);
socket.server();
};
}.start();
}
});
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0)
receiveTxt.setText((String) msg.obj);
else if (msg.what == 1) {
sendTxt.setText((String) msg.obj);
}
};
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
记得在AndroidManifest.xml里加入权限
<!-- 允许应用程序改变网络状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 允许应用程序改变WIFI连接状态 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 允许应用程序访问有关的网络信息 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许应用程序访问WIFI网卡的网络信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许应用程序完全使用网络 -->
<uses-permission android:name="android.permission.INTERNET" />