本文对Socket作简单的整理:
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。抽象出来,Socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。
下面是Socket 的Java实现:
一:服务器端的实现
<span style="font-size:18px;"> public static int PORT = 8080;
public static void main(String[] agrs) {
ServerSocket s = null;
Socket socket = null;
BufferedReader br = null;
PrintWriter pw = null;
try {
// 设定服务端的端口号
s = new ServerSocket(PORT);
System.out.println("ServerSocket Start:" + s);
// 等待请求,此方法会一直阻塞,直到获得请求才往下走
socket = s.accept();
System.out.println("Connection accept socket:" + socket);
// 用于接收客户端发来的请求
br = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 用于发送返回信息,可以不需要装饰这么多io流使用缓冲流时发送数据要注意调用.flush()方法
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
while (true) {
String str = br.readLine();
if (str.equals("END")) {
break;
}
System.out.println("Client Socket Message:" + str);
Thread.sleep(1000);
pw.println("Message Received");
pw.flush();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("Close.....");
try {
br.close();
pw.close();
socket.close();
s.close();
} catch (Exception e2) {
}
}
}</span>
二:客户端的实现
<span style="font-size:18px;"> public static void main(String[] args) {
Socket socket = null;
BufferedReader br = null;
PrintWriter pw = null;
try {
//客户端socket指定服务器的地址和端口号
socket = new Socket("127.0.0.1",8080);
System.out.println("Socket=" + socket);
//同服务器原理一样
br = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
for (int i = 0; i < 10; i++) {
pw.println("client " + i);
pw.flush();
String str = br.readLine();
System.out.println(str);
}
pw.println("END");
pw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("close......");
br.close();
pw.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} </span>
三:Android客户端的实现,我们一般写在事件回调中
<span style="font-size:18px;"> button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Socket socket = null;
String message = editText.getText().toString()+ "\r\n" ;
try {
//创建客户端socket,注意:不能用localhost或127.0.0.1,Android模拟器把自己作为localhost
socket = new Socket("10.62.13.243",9192);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
//发送数据
out.println(message);
//接收数据
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = in.readLine();
if (null != msg){
editText.setText(msg);
System.out.println(msg);
}
else{
editText.setText("data error");
}
out.close();
in.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
if (null != socket){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}); </span>
上面的代码还是比较简单的
四:socket的缺点:
传统socket:阻塞式通信
每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。
这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果
对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。
五:针对Socket的缺点,Java提出了nio:非阻塞通讯模式
NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式。
反应器模式的核心功能如下:
将事件多路分用 将事件分派到各自相应的事件处理程序
NIO 的非阻塞 I/O 机制是围绕 选择器和 通道构建的。 Channel 类表示服务器和客户机之间的
一种通信机制。Selector 类是 Channel 的多路复用器。 Selector 类将传入客户机请求多路分
用并将它们分派到各自的请求处理程序。
通道(Channel 类):表示服务器和客户机之间的一种通信机制。
选择器(Selector类):是 Channel 的多路复用器。Selector 类将传入的客户机请求多路分用并将它们
分派到各自的请求处理程序。
简单的来说:
NIO是一个基于事件的IO架构,最基本的思想就是:有事件我通知你,你再去做你的事情.而且NIO的主线程只有一个,不像传统的模型,需要多个线程以应对客户端请求,也减轻了JVM的工作量。
针对NIO这种思想,目前已经有了比较成熟的框架:Apache MINA.
本文的例子下载