Android中socket的应用
2016-07-11 16:57
561 查看
最近我在做一些关于实时网络双向通信的小玩意,于是开始接触用到了socket。 一开始看看socket的代码觉得并不难,但实际操作时候还是遇到不少问题,所以还是觉得好好整理一下socket在Android程序中的用法吧。
首先,什么是socket呢?百度百科上的解释是网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。简要的说socket就是一个接口,基于TCP/IP协议,用来实现服务器端与客户端之间双向传输数据。
我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。
如图所示,服务器端先根据当前IP地址创建Serversocket并绑定端口号,监听着端口号的请求(此时服务器的socket还没打开),进入堵塞状态。然后客户端建立socket,并且根据IP和端口号寻找试图连接服务器。服务器接收到客户端的请求,通过”三次握手“,双方建立连接,接下来就可以进行数据交互,直到最后关闭。
对于这个流程,简单来说就是座山雕坐在威虎山(对应IP)头号交椅上(对应端口号)等着小弟报告信息(监听处于阻塞状态,即知道小弟会来但是不知道小弟什么时候会来,于是等着但是没做其他事)。这时候呢杨子荣找着来到了威虎山头号交椅前,说,拜见大爷(客户端尝试连接服务器,向服务器发送syn包,进入SYN_SEND状态等待服务器确认)。座山雕收到信息回复:天王盖地虎(服务器接收客户端syn包并确认,同时向客户端发送一个SYN包)。杨子荣回答,小鸡炖蘑菇(客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK)。然后两人确定身份,建立了socket连接。
建立了连接以后呢,就好像服务器和客户端之间修了一条公路。公路的特点是什么呢?两条道,每条道上都是单向行驶,两条道的行驶互不影响,路的两头互为终起点。好吧,这四点大概就是socket传输时候的几个特点吧,不过有一点注意的是,无论服务器端还是移动端,当处于read()时候都是处于阻塞状态,所以客户端最好是先write再read,避免出现同时阻塞的情况。
接下来放点干货吧,先上服务端:
package
test5;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import net.yrom.screenrecorder.InputObject;
public class Server5 {
boolean started = false;//判断Serversocket是否开启
boolean delete=false;//判断是否有客户端退出
int j=-1;
ServerSocket ss = null;
List<Client> clients = new ArrayList<Client>();
public static void main(String[] args) {
new ChatServer5().start();
}
public void start() {
try {
ss = new ServerSocket(9999);
started = true;
System.out.println("端口已开启,占用9999端口号....");
} catch (BindException e) {
System.out.println("端口使用中....");
System.out.println("请关掉相关程序并重新运行服务器!");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
try {
while (started) {
Socket s = ss.accept();//此步处于一个阻塞状态
Client c = new Client(s);
new Thread(c).start();//每个连接的客户端开启一个新的线程
clients.add(c);
System.out.println("第"+clients.size()+"个客户端连接进来了");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Client implements Runnable {
private Socket s;
private ObjectInputStream ois=null;
private ObjectOutputStream oos=null;
private boolean bConnected = false;
public Client(Socket s) {
this.s = s;
try {
ois = new ObjectInputStream(s.getInputStream());
oos =new ObjectOutputStream(s.getOutputStream());
bConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(InputObject ibj,int i) {
try {
// System.out.println("write");
oos.writeUnshared(ibj);
oos.flush();
} catch (IOException e) {
delete=true;
j=i;
System.out.println("有一个客户端退出了!我从List里面去掉了!");
}
}
public void run() {
try {
while (bConnected) {
Object obj=new Object();
// System.out.println("read");
obj= ois.readObject();//此时处于一个阻塞状态
InputObject inputobject=new InputObject();
inputobject= (InputObject)obj;
System.out.println("------------来自客户端的信息:长度" + inputobject.getSize());
for (int i = 0; i < clients.size(); i++) {
Client c = clients.get(i);
if (c!=this){
c.send(inputobject,i);
}
}
if(delete){
try
{
clients.remove(j);
delete=false;
System.out.println("此时还有" + clients.size()+"个客户端连接");
}catch(Exception e){
e.printStackTrace();
}
}
}
}catch(ClassNotFoundException ex) {
ex.printStackTrace();
}catch (EOFException e) {
clients.remove(this);
System.out.println("Socket关闭了");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ois != null)
ois.close();
if (oos != null)
oos.close();
if (s != null) {
s.close();//关闭socket
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
这段代码我注释还是比较详细的,简要说就是建立个servicesocket,接受信息,并将每个建立的socket放在一个线程里,当有一个客户端给服务器发送信息时候,服务器将受到的信息再转发给其他的所有客户端。
然后是客户端的代码,这块在我的程序里做的有点散,而且发送和接受是分开的,我就剥离一些功能出来说明下吧:
首先是建立个socket,连接IP和端口号,设置超时,初始化输出,初始化自定义对象:
然后是将要发的信息放在自定义对象里:
接着就是发送了:
最后就是发送完毕以后,关闭socket。
对于接收端,我是这样写的:
首先也是创建socket:
然后就是获取并关闭了:
因为都是截取的,有点乱,不过这两个合并整理下也就差不多是客户端的代码了。
首先,什么是socket呢?百度百科上的解释是网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。简要的说socket就是一个接口,基于TCP/IP协议,用来实现服务器端与客户端之间双向传输数据。
我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。
如图所示,服务器端先根据当前IP地址创建Serversocket并绑定端口号,监听着端口号的请求(此时服务器的socket还没打开),进入堵塞状态。然后客户端建立socket,并且根据IP和端口号寻找试图连接服务器。服务器接收到客户端的请求,通过”三次握手“,双方建立连接,接下来就可以进行数据交互,直到最后关闭。
对于这个流程,简单来说就是座山雕坐在威虎山(对应IP)头号交椅上(对应端口号)等着小弟报告信息(监听处于阻塞状态,即知道小弟会来但是不知道小弟什么时候会来,于是等着但是没做其他事)。这时候呢杨子荣找着来到了威虎山头号交椅前,说,拜见大爷(客户端尝试连接服务器,向服务器发送syn包,进入SYN_SEND状态等待服务器确认)。座山雕收到信息回复:天王盖地虎(服务器接收客户端syn包并确认,同时向客户端发送一个SYN包)。杨子荣回答,小鸡炖蘑菇(客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK)。然后两人确定身份,建立了socket连接。
建立了连接以后呢,就好像服务器和客户端之间修了一条公路。公路的特点是什么呢?两条道,每条道上都是单向行驶,两条道的行驶互不影响,路的两头互为终起点。好吧,这四点大概就是socket传输时候的几个特点吧,不过有一点注意的是,无论服务器端还是移动端,当处于read()时候都是处于阻塞状态,所以客户端最好是先write再read,避免出现同时阻塞的情况。
接下来放点干货吧,先上服务端:
package
test5;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import net.yrom.screenrecorder.InputObject;
public class Server5 {
boolean started = false;//判断Serversocket是否开启
boolean delete=false;//判断是否有客户端退出
int j=-1;
ServerSocket ss = null;
List<Client> clients = new ArrayList<Client>();
public static void main(String[] args) {
new ChatServer5().start();
}
public void start() {
try {
ss = new ServerSocket(9999);
started = true;
System.out.println("端口已开启,占用9999端口号....");
} catch (BindException e) {
System.out.println("端口使用中....");
System.out.println("请关掉相关程序并重新运行服务器!");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
try {
while (started) {
Socket s = ss.accept();//此步处于一个阻塞状态
Client c = new Client(s);
new Thread(c).start();//每个连接的客户端开启一个新的线程
clients.add(c);
System.out.println("第"+clients.size()+"个客户端连接进来了");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Client implements Runnable {
private Socket s;
private ObjectInputStream ois=null;
private ObjectOutputStream oos=null;
private boolean bConnected = false;
public Client(Socket s) {
this.s = s;
try {
ois = new ObjectInputStream(s.getInputStream());
oos =new ObjectOutputStream(s.getOutputStream());
bConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(InputObject ibj,int i) {
try {
// System.out.println("write");
oos.writeUnshared(ibj);
oos.flush();
} catch (IOException e) {
delete=true;
j=i;
System.out.println("有一个客户端退出了!我从List里面去掉了!");
}
}
public void run() {
try {
while (bConnected) {
Object obj=new Object();
// System.out.println("read");
obj= ois.readObject();//此时处于一个阻塞状态
InputObject inputobject=new InputObject();
inputobject= (InputObject)obj;
System.out.println("------------来自客户端的信息:长度" + inputobject.getSize());
for (int i = 0; i < clients.size(); i++) {
Client c = clients.get(i);
if (c!=this){
c.send(inputobject,i);
}
}
if(delete){
try
{
clients.remove(j);
delete=false;
System.out.println("此时还有" + clients.size()+"个客户端连接");
}catch(Exception e){
e.printStackTrace();
}
}
}
}catch(ClassNotFoundException ex) {
ex.printStackTrace();
}catch (EOFException e) {
clients.remove(this);
System.out.println("Socket关闭了");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ois != null)
ois.close();
if (oos != null)
oos.close();
if (s != null) {
s.close();//关闭socket
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
这段代码我注释还是比较详细的,简要说就是建立个servicesocket,接受信息,并将每个建立的socket放在一个线程里,当有一个客户端给服务器发送信息时候,服务器将受到的信息再转发给其他的所有客户端。
然后是客户端的代码,这块在我的程序里做的有点散,而且发送和接受是分开的,我就剥离一些功能出来说明下吧:
首先是建立个socket,连接IP和端口号,设置超时,初始化输出,初始化自定义对象:
//连接服务器 并设置连接超时为5秒 socket = new Socket(); socket.connect(new InetSocketAddress("192.168.1.13", 9999), 5000); // ois =new ObjectInputStream(socket.getInputStream()); dos=new DataOutputStream(socket.getOutputStream());// inputObject=new InputObject(); oos=new ObjectOutputStream(socket.getOutputStream());
然后是将要发的信息放在自定义对象里:
inputObject.setSize(jj); inputObject.setByteBuffer(b);
接着就是发送了:
try { oos.writeUnshared(inputObject); oos.flush(); } catch (SocketTimeoutException aa) { aa.printStackTrace(); //连接超时 在UI界面显示消息 //发送消息 修改UI线程中的组件 } catch (IOException e) { e.printStackTrace(); } catch(Exception ex) { ex.printStackTrace(); }
最后就是发送完毕以后,关闭socket。
finally { try{ if (socket!=null){ socket.close(); } }catch (IOException eo){ eo.printStackTrace(); } }
对于接收端,我是这样写的:
首先也是创建socket:
socket = new Socket(); socket.connect(new InetSocketAddress("192.168.1.13", 9999), 5000); oos=new ObjectOutputStream(socket.getOutputStream()); ois =new ObjectInputStream(socket.getInputStream());
然后就是获取并关闭了:
try {
while (true) {
Object obj = ois.readObject();
InputObject inputobject = (InputObject) obj;
int size = inputobject.getSize();
byte[] bytes = inputobject.getByteBuffer();
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
}
}catch (Exception e) {
e.printStackTrace();
}finally { try{ if (socket!=null){ socket.close(); } }catch (IOException eo){ eo.printStackTrace(); } }
因为都是截取的,有点乱,不过这两个合并整理下也就差不多是客户端的代码了。
相关文章推荐
- SlidingActivity 手势控制Activity切换
- Android APK打包流程
- Android通过注解初始化View
- Android开发——Intent中的各种FLAG
- android中Context的作用
- Android 打造形形色色的进度条 实现可以如此简单
- android 自定义Textview多层边框,实现了文字内容闪烁的功能!
- 自己认为好的博客(java+Android)
- (4.2.33.1)Android上玩玩Hook(2):Cydia Substrate演练
- Android--添加阴影效果--CardView的使用
- Android 跨进程内存泄露
- Android MediaCodec 的实例化方法
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android基础&进阶-----基础总结篇汇总
- com/android/dx/command/dexer/Main : Unsupported major.minor version 52.0
- 文章标题
- 使用WIFI连接android进行调试和adb操作
- Android 使用OpenSSL进行3DES加密 c与java互通
- Android 自定义View (四) 视频音量调控
- Android 渐变色