在客户端和服务器端通信模式中,可以使用ServerSocket对象来构建TCP服务端。服务端需要创建监听特定端口的ServerSocket,ServerSocket负责接收客户连接请求,并生成与客户端连接的Socket。
ServerSocket类的构造方法说明如下:
ServerSocket()
该构造方法创建一个未绑定的服务器套接字。
ServerSocket(int port)
该构造方法创建绑定到指定端口的服务器套接字。参数port为指定的端口号。套接字的默认绑定IP地址为0.0.0.0,用来表示本机任意的ipv4地址。
ServerSocket(int port, int backlog)
该构造方法创建服务器套接字并将其绑定到具有指定backlog的指定本地端口号。参数port为端口号,参数backlog为请求传入连接队列的最大长度。如果连接请求在队列已满时到达,则连接将被拒绝。套接字的默认绑定IP地址为0.0.0.0,用来表示本机任意的ipv4地址。
ServerSocket(int port, int backlog, InetAddress bindAddr)
该构造方法使用指定的端口、侦听backlog和要绑定到的指定的IP地址创建服务器。参数bindAddr为指定IP地址的InetAddress对象。
ServerSocket类的常用方法说明如下:
Socket accept()
该方法用于侦听与此套接字的连接请求,并接收该请求,该方法将阻塞,直到建立连接。该方法将返回一个新的套接字。
InetAddress getInetAddress()
该方法返回此服务器套接字的本地地址。如果套接字在关闭前已绑定,则此方法将在套接字关闭后继续返回本地地址。
void bind(SocketAddress endpoint)
该方法将服务器套接字绑定到特定地址(IP地址和端口号)。如果地址为空,那么系统将获取一个临时端口和一个有效的本地地址来绑定套接字。参数endpoint是SocketAddress类型,指定了要绑定的IP地址和端口号。
boolean isBound()
该方法返回服务器套接字的绑定状态。
InetAddress getInetAddress()
该方法返回此服务器套接字的本地地址。
int getLocalPort()
该方法返回此套接字侦听的端口号。
void close()
该方法关闭该套接字。关闭该套接字后,当前在accept()塞的任何线程都将抛出SocketException。
在服务器端创建ServerSocket对象,并绑定监听端口。调用ServerSocket对象的accept()方法监听客户端的请求。与客户端建立连接后,通过输入流读取客户端发送的请求信息,然后通过输出流向客户端发送响应信息,最后关闭socket及相关资源。
案例1:编写一个TCP服务端程序。建立TcpServer类,在TcpServer类中创建套接字,侦听指定的端口,等待连接请求。
在PCoreUnit11项目新建tcp包,在tcp包下新建TcpServer类。代码如下:
package tcp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @ClassName: TcpServer
* @Description: 网络编程(构建TCP服务器)案例1
* @author 编程训练营
* @date
*
*/
public class TcpServer {
// 定义ServerSocket对象
ServerSocket serverSocket = null;
// 定义端口号
int port;
// 构造方法
public TcpServer() {
this.port = 9099;
}
/**
* @Title: getIp
* @Description: 获取服务器的IP地址
* @param @return 参数
* @return String 返回类型
* @throws
*/
public String getIp()
{
if( null != serverSocket )
{
InetAddress address = serverSocket.getInetAddress();
return address.getHostAddress();
}
return "";
}
/**
* @Title: init
* @Description: 初始化和启动服务器
* @param 参数
* @return void 返回类型
* @throws
*/
public void init() {
System.out.println("服务器启动...");
try {
/**
* 创建一个ServerSocket,这里可以指定连接请求的队列长度 new ServerSocket(port,3)
* 意味着当队列中有3个连接请求时,如果客户端再请求连接,就会被服务器拒绝
*/
serverSocket = new ServerSocket(port, 3);
// 服务器循环监听连接请求
while (true) {
// 从请求队列中取出一个客户端的连接请求
Socket client = serverSocket.accept();
// 建立一个新线程处理这次连接
new HandlerThread(client);
}
} catch (Exception e) {
System.out.println("服务器异常: " + e.getMessage());
}
}
/**
* @ClassName: HandlerThread
* @Description: 客户端请求线程处理类
* @author 编程训练营
* @date
*
*/
private class HandlerThread implements Runnable {
// 定义socket
Socket socket;
// 构造方法
public HandlerThread(Socket socket) {
this.socket = socket;
// 启动线程
new Thread(this).start();
}
/**
* <p>
* Title: run
* </p>
* <p>
* Description:
* </p>
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try {
// 读取客户端数据
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 这里要注意和客户端输出流的写方法对应,否则会抛 EOFException
String clientInputStr = input.readLine();
// 处理客户端数据
System.out.println("客户端发过来的内容:" + clientInputStr);
// 向客户端回复信息
PrintStream out = new PrintStream(socket.getOutputStream());
System.out.print("请输入:\t");
// 发送键盘输入的一行
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
out.println(s);
out.close();
input.close();
} catch (Exception e) {
System.out.println("服务器 run 异常: " + e.getMessage());
} finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
socket = null;
System.out.println("服务端 finally 异常:" + e.getMessage());
}
}
}
}
}
}编写TCP服务端程序的主要步骤如下:
(1) 实例化ServerSocket对象,创建套接字;
(2) 调用ServerSocket对象的accept()方法监听端口;
(3) accept()方法监听到连接请求后,会返回Socket对象,accept()是堵塞方法,如果没有客户端的连接请求,方法后面的代码不会执行;
(4) 建立一个新的线程,利用I/O流与客户端进行通信,
(5) 通信完成后,关闭Socket。
在tcp包下新建TcpServerTest测试类,启动服务器。代码如下:
package tcp;
/**
* @ClassName: TcpServerTest
* @Description: 网络编程(构建TCP服务器)案例1
* @author 编程训练营
* @date
*
*/
public class TcpServerTest {
/**
* @Title: main
* @Description: Java程序入口main方法
* @param @param args 参数
* @return void 返回类型
* @throws
*/
public static void main(String[] args) {
// 实例化TcpServer对象
TcpServer tcpserver = new TcpServer();
// 启动服务
tcpserver.init();
}
}程序TcpServerTest实例化TcpServer对象,并调用TcpServer对象的init()方法启动服务器。