在开始编写代码之前,先来看看socket的通信模型
a.首先写一个socket服务端如下:
public class ServerSocket1 {
/**
*1、创建ServerSocket对象,同时绑定监听端口
* 2、通过accept()方法监听客户端的请求
* 3、建立连接后,通过输入流读取客户端发送的请求信息
* 4、通过输出流向客户端发送响应信息
* 5、关闭相应资源
*/
public static void main(String[] args)throws Exception {
//1.创建一个服务端Socket,即ServerSocket对象,指定绑定的端口,并侦听该端口
ServerSocket serverSocket=new ServerSocket(5555);
//2.调用accept()方法开始侦听客户端请求,创建Socket,等待客户端的连接
System.out.println("==============服务即将启动,等待客户端的连接===========");
/**
* 此处会阻塞,等待客户端调用
*/
Socket socket=serverSocket.accept();
//3.获取输入字节流,读取客户端请求信息
InputStream is=socket.getInputStream();
//将字节流包装成字符流
InputStreamReader isr=new InputStreamReader(is);
//为字符输入流添加缓冲
BufferedReader br=new BufferedReader(isr);
//读取字符输入流中的信息
String data=null;
while(null!=(data=br.readLine())){
System.out.println(new Date());
System.out.println("我是服务端,客户端说:"+data);
}
//调用shutdown方法关闭输入流流
socket.shutdownInput();
//4.获取输出字节流,响应客户端的信息
OutputStream os=socket.getOutputStream();
//将字节流包装成字符打印流
PrintWriter pw=new PrintWriter(os);
//向客户端回应响应消息
pw.write("用户名的密码输入不正确");
pw.flush();
//关闭socket输出流
socket.shutdownOutput();
//关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
}
}
b.在写一个socket客户如下:
public class SocketClient {
/**
* 1.创建Socket对象
* 2.建立连接后,通过输出流向服务器发送请求信息
* 3.通过输入流获取服务器的响应信息
* 4.关闭资源
*/
public static void main(String[] args) throws Exception{
//1.创建Socket对象
Socket socket=new Socket("127.0.0.1",5555);
//2.获取输出字节流,向服务器发送消息
OutputStream os=socket.getOutputStream();
//将字节输出流包装为字符打印流
PrintWriter pw=new PrintWriter(os);
//向服务器发送请求信息
StringBuffer sb=new StringBuffer();
sb.append("用户名:").append("admin");
sb.append("密码:").append("123");
pw.write(sb.toString());
pw.flush();
//关闭socket的输出流
socket.shutdownOutput();
//3.获取输入字节流,读取服务器的响应信息
InputStream is=socket.getInputStream();
//将输入字节流包装成字符流
InputStreamReader isr=new InputStreamReader(is);
//为字符流添加缓冲区
BufferedReader br=new BufferedReader(isr);
//通过服务器端的响应信息
String data=null;
while(null!=(data=br.readLine())){
System.out.println(new Date());
System.out.println("我是客户端,服务端说:"+data);
}
//关闭Socket输入流
socket.shutdownInput();
//4、关闭资源
br.close();
isr.close();
is.close();
pw.close();
os.close();
socket.close();
}
}
以上就完成了基本的socket客户端与服务端的程序。但是该程序的服务端只能完成一次socket请求。
下面对服务器的改造可以完成对客户端的多次请求如下:
a.首先编写一个接受到请求的处理类
/**
* 创建一个服务端线程,循环侦听客户端的请求
*/
public class ServerThread extends Thread {
//每当侦听到一个新的客户端时,服务端都需要有一个Socket与之通信
public Socket socket = null;
public ServerThread() {
}
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//获取输入字节流
InputStream in = null;
//将输入字节流包装成输入字符流
InputStreamReader isr = null;
//为字符输入流添加缓冲
BufferedReader br = null;
//收到信息之后,向客户端响应信息,获取输出字节流
OutputStream out = null;
//将字节输出流包装成字符打印输出流
PrintWriter pw = null;
try {
in = socket.getInputStream();
isr = new InputStreamReader(in);
br = new BufferedReader(isr);
//读取字符输入流中的数据
String data = null;
while ((data = br.readLine()) != null) {
System.out.println("我是服务器,客户端说:" + data);
}
//调用shutDown方法关闭Socket输入流
socket.shutdownInput();
out = socket.getOutputStream();
pw = new PrintWriter(out);
pw.write("用户名和密码正确");
pw.flush();
//调用shutDown方法关闭Socket输出流
socket.shutdownOutput();
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
try {
if (null != pw)
pw.close();
if (null != out)
out.close();
if (null != br)
br.close();
if (null != isr)
isr.close();
if (null != in)
in.close();
if (null != socket)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
b.然后在启用服务端程序来接受请求
public class ServerSocketMany {
public static void main(String[] args)throws Exception{
System.out.println("服务器已经启动,等待客户端的连接");
//创建服务器端Socket,即ServerSocket等待客户端请求
ServerSocket server=new ServerSocket(5555);
//侦听到的客户端的数量
int count=0;
//服务器socket
Socket socket=null;
//死循环,让服务器循环侦听
while(true){
//服务端开始侦听客户端的连接
socket=server.accept();
//启动线程,与客户端进行通信
Thread serverThread=new ServerThread(socket);
serverThread.start();
//计数
count++;
System.out.println("当前链接的客户端的数量为:"+count+"个....");
}
}
}
c.编写客户端:客户端和上一个版本没有区别。
上文参考博客:http://blog.csdn.net/hu1991die/article/details/40679605
另外:tomcat中的等待连接的实现思路如下:
当有一个请求到达后,tomcat的连接对象,接受该处理后,立马转接到一个线程处理,然后退出该方法,通过此种方式完成了方法的等效异步调用