由于一直以来都在使用Java进行Web相关的开发工作,平常写的比较多的都是servlet,或者是基于servlet(或filter)的框架(springmvc、struts2等)。这些程序都需要运行在像tomcat、weblogic等web服务器(servlet容器)中,web容器负责端口的监听、HTTP请求的接收和返回、并发的处理等工作,程序员们更多的是负责业务逻辑的编写。这样虽然降低了web编程的门槛,却使得很多程序员对网络通信方面的知识一无所知。所以今天整理一下有关java socket编程的文字,便于自己的回顾和进步。
什么是Socket?百度百科上是这样解释的,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。我们知道,目前的互联网是遵循TCP/IP协议族的,数据要想在两台计算机间进行传输,就必须经过应用层、传输层、网络层、数据链路层的层层编码、解码以及各种复杂操作。而socket就是应用层和传输层之间的一个抽象层,他把传输层、网络层等复杂的操作抽象为几个简单的接口供应用层调用,如下图1-1(图片取自互联网)。也就是说,socket是TCP/IP的一个编程界面,它屏蔽了设备通信的细节。socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。
图1-1
Socket的通信过程可描述如下:首先,服务端创建一个固定的Socket(使用协议、本地地址和本地端口进行相关描述),并且时刻监听这其绑定的端口的网络状态,等待客户端的连接。客户端随机申请一个Socket,发出连接请求,请求的目标为固定的服务端的Socket。为此,客户端的Socket必须首先描述它要连接的服务器的Socket,指出服务器端Socket的地址和端口号,然后就向服务器端Socket提出连接请求。服务端Socket一旦接受到客户端的soket的连接请求,三次握手成功以后(accept),就会创建一个新的socket与其进行通信,socket和socket之间是双向连通的。其实,Socket所支持的协议种类也不仅仅是TCP/IP。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
Socket代码示例(基于TCP协议):
Server端:
public class Server {
private static final int port = 8888;
public static void main(String[] args) {
ServerSocket server = null;
Socket socket = null;
try{
server = new ServerSocket(port);
System.out.println("server open in port:" + port);
while(true){
socket = server.accept(); //accept方法是阻塞的
InputStream in = new BufferedInputStream(socket.getInputStream());
byte[] b = new byte[256];
int len = 0;
StringBuilder sb = new StringBuilder();
//read方法同样是阻塞的,读到数据就会执行循环体,否则就会一直阻塞
//这样的话,后面的写操作就永远都执行不了,除非客户端关闭socket
//所以我们一般会约定一个结束标记,如下面的.
while((len=in.read(b)) != -1){
String str = new String(b,0,len);
sb.append(str);
if(str.endsWith(".")){
break;
}
}
System.out.println("request : " + sb.toString());
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
String response = "hello," + sb.toString();
out.write(response.getBytes());
out.flush(); //写完要记得flush
in.close();
out.close();
socket.close();
}
}catch(IOException e){
e.printStackTrace();
try {
if(socket != null) socket.close();
if(server != null) server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Client端:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",8888);
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
out.write("leo".getBytes());
out.flush();
out.write(",daniel.".getBytes()); //服务端遇到.才会跳出while循环
out.flush();
InputStream in = new BufferedInputStream(socket.getInputStream());
int len = 0;
byte[] b = new byte[256];
StringBuilder sb = new StringBuilder();
while((len=in.read(b)) != -1){
sb.append(new String(b,0,len));
}
System.out.println("response : " + sb.toString());
out.close();
in.close();
socket.close();
}
}
本篇文字对Socket进行了解释,并且给出了Socket编程的简单示例,Socket服务端只是采用了一个很简单的单线程阻塞的IO模型,一次只能接收一个客户端请求,在实际的生产环境中是不能使用的。但本篇文章重点在于讲解Socket相关的基础知识,不涉及到相关的各种IO通信模型的讲解,以后会抽时间进行整理IO通信模型相关的知识。
参考文档:http://www.cnblogs.com/dolphinX/p/3460545.html