在java中使用Socket (即套接字)完成TCP程序的开发,使用此类可以方便的建立可靠的、双向的、持续的、点对点的通信连接。
在Socket的程序开发中,服务器端使用ServerSocket 等待客户端的连接,对于java的网络程序来讲,每一个客户端都使用一个Socket 对象表示,通过accept() 方法进行连接。
一:ServerSocket 类 与 Socket 类
1、用法及实现范例
ServerSocket类主要用在服务器端程序的开发商,用于接收客户端的连接请求,在服务器端每次运行时都要使用accept() 方法等待客户端连接,此方法执行之后,服务器端将进入阻塞状态,直到客户端连接之后程序才可以向下继续执行。此方法返回值类型是 Socket ,每一个 Socket 都表示一个客户端对象。
在客户端,程序可以通过 Socket 类的 getInputStream() 方法取得服务器的输出信息,在服务器端可以通过 getOutputStream() 方法取得客户端的输出信息。
范例1:
package haizhu.com.socket;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDemo01 {
public static void main(String[] args) throws Exception{
String str = "Hello world !";
ServerSocket server = null; // 声明ServerSocket对象
Socket client = null; // 一个Socket 对象表示一个客户端
PrintStream out = null; // 声明打印流对象,以向客户端输出
server = new ServerSocket(8888); // 此时服务器在8888端口等待客户端的访问
System.out.println("服务器运行,等待客户端连接。");
client = server.accept(); // 程序阻塞,等待客户端的连接
out = new PrintStream(client.getOutputStream());//实例化打印流对象,输出信息
out.println(str); // 输出信息
out.close(); // 关闭打印流
client.close(); // 关闭客户端连接
server.close(); // 关闭服务器连接
}
}
package haizhu.com.socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
public class ClientSocketDemo01 {
public static void main(String[] args) throws Exception{
Socket client = null; // 声明Socket对象
client = new Socket("localhost",8888); // 指定连接主机和端口
BufferedReader buf = null; // 声明 BufferedReader对象,接收信息
buf = new BufferedReader(
new InputStreamReader(
client.getInputStream())); // 取得客户端的输入流
String str = buf.readLine(); // 读取信息
System.out.println("服务器端输出内容:"+str);
client.close(); // 关闭Socket
buf.close(); // 不安比输入流
}
}
ServerSocketDemo01 执行到 accept() 方法后,程序进入到阻塞状态,此阻塞状态会在客户端连接之后改变。运行ClentSocketDemo01 之后,第一个方法才继续运行,然后打印出 str 结束。
上面程序的主要结构是:服务器端启动ServerSocket,启动创建客户端Socket对象,并使用getInputStream 接收内容。等待调用这个Socket对象并调用getOutputStream方法打印出接收的内容。
2、Echo程序
这是网络编程通信交互的一个经典案例,称为回应程序,即客户端输入哪些内容,服务器端会在这些内容前加上“ECHO:”并将信息发回客户端,下面就完成这样的一个程序。
上面的程序,服务端每次执行完毕后服务器都会退出,这是因为服务器端只能接收一个客户端的连接,主要是由于accept() 方法只能使用一次。本程序中将通过循环的方式使用accept() ,这样,每一个客户端执行完毕后,服务器端都可以重新等待用户连接。
范例2:
package haizhu.com.socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
public static void main(String[] args) throws Exception{
ServerSocket server = null;
Socket client = null;
PrintStream out = null;
BufferedReader buf = null;
server = new ServerSocket(8888);
Boolean t = true;
while(t){
System.out.println("服务器正在运行,等待客户端连接。");
client = server.accept();
buf = new BufferedReader(
new InputStreamReader(
client.getInputStream()));
out = new PrintStream(
client.getOutputStream());
boolean flag = true;
while(flag){
String str = buf.readLine();
if(str == null || "".equals(str)){
flag = false;
}else{
if("bye".equals(str)){
flag = false;
}else{
out.println("ECHO:"+str);
}
}
}
out.close();
client.close();
}
server.close();
}
}
package haizhu.com.socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class EchoClient {
public static void main(String[] args) throws Exception{
Socket client = null;
client = new Socket("localhost",8888);
BufferedReader buf = null;
PrintStream out = null;
BufferedReader input = null;
input = new BufferedReader(
new InputStreamReader(System.in));
out = new PrintStream(client.getOutputStream());
buf = new BufferedReader(
new InputStreamReader(
client.getInputStream()));
boolean flag = true;
while(flag){
System.out.println("输入信息:");
String str = input.readLine();
out.println(str);
if("bye".equals(str)){
flag = false;
} else {
String echo = buf.readLine();
System.out.println(echo);
}
}
client.close();
buf.close();
}
}
3、多线程网络编程
上面的例子虽然能够接收多条信息,但是一次只能连接一个客户端,要想连接多个客户端,就需要使用多线程:
范例3:
package haizhu.com.socket;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServerThread {
public static void main(String[] args) throws Exception{
ServerSocket server = null;
Socket client = null;
server = new ServerSocket(8888);
Boolean t = true;
while(t){
System.out.println("服务器正在运行,等待客户端连接。");
client = server.accept();
new Thread(new EchoClientThread(client)).start();
}
server.close();
}
}
package haizhu.com.socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class EchoClientThread implements Runnable{
private Socket client = null;
public EchoClientThread(Socket client){
this.client = client;
}
public void run(){
PrintStream out = null;
BufferedReader buf = null;
try{
buf = new BufferedReader(
new InputStreamReader(
client.getInputStream()));
out = new PrintStream(
client.getOutputStream());
boolean flag = true;
while(flag){
String str = buf.readLine();
if(str == null || "".equals(str)){
flag = false;
}else{
if("bye".equals(str)){
flag = false;
} else {
out.println("ECHO:"+str);
}
}
}
out.close();
client.close();
}catch(Exception e){
e.printStackTrace();
}
}
}