天天看点

Java Socket和ServerSocket通信服务器 聊天功能 的实现

在客户/服务器通信模式中,服务器端需要创建监听特定端口的ServerSocket,ServerSocket负责接收客户连接请求。首先介绍ServerSocket类的各个构造方法,以及成员方法的用法,接着介绍服务器如何用多线程来处理与多个客户的通信任务。

ServerSocket的构造方法有以下几种重载形式:

◆ServerSocket()throws IOException 
◆ServerSocket(int port) throws IOException 
◆ServerSocket(int port, int backlog) throws IOException
◆ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
           

在以上构造方法中,参数port指定服务器要绑定的端口(服务器要监听的端口),参数backlog指定客户连接请求队列的长度,参数bindAddr指定服务器要绑定的IP地址。

除了第一个不带参数的构造方法以外,其他构造方法都会使服务器与特定端口绑定,该端口由参数port指定。例如,以下代码创建了一个与9999端口绑定的服务器:

ServerSocket serverSocket=new ServerSocket(9999);
           

如果运行时无法绑定到80端口,以上代码会抛出IOException,更确切地说,是抛出BindException,它是IOException的子类。BindException一般是由以下原因造成的:

◆端口已经被其他服务器进程占用;

◆在某些操作系统中,如果没有以超级用户的身份来运行服务器程序,那么操作系统不允许服务器绑定到1~1023之间的端口。0~1023之间的端口是用于绑定Binding的一些服务的端口。

如果把参数port设为0,表示由操作系统来为服务器分配一个任意可用的端口。由操作系统分配的端口也称为匿名端口。对于多数服务器,会使用明确的端口,而不会使用匿名端口,因为客户程序需要事先知道服务器的端口,才能方便地访问服务器。

聊天服务器小Demo

/**
 * ServerSocket简单聊天服务器
 * @author 钟宇峰
 */
public class ServerDemo  {
	private Socket socket;
	private ServerSocket server;
	//主函数
	public static void main(String[] args) {
		ServerDemo sd = new ServerDemo();
		sd.createServer(9999);
	}
	/**
	 * 创建服务器
	 * @param port 端口号
	 */
	public void createServer(int port){
		try {
			//创建服务器
			 server = new ServerSocket(port);
			System.out.println("服务器创建成功....");
			System.out.println("服务器处于阻塞状态中,等待客户机连接.....");
			//服务器阻塞中等待客户机连接
			whlie(true){
				socket = server.accept();
				System.out.println("客户机"+(i-1)+"连接成功!"+socket.getRemoteSocketAddress());
				ClientDemo cd = new ClientDemo(server,socket);
				cd.start();
			}
			//客户机已连接
			server.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
-----------------------------------------------------------------------------
public class ClientDemo extends Thread {
	private ServerSocket server;
	private Socket socket;

	public ClientDemo(ServerSocket server, Socket socket) {
		this.socket = socket;
		this.server = server;
	}

	public void run() {
		while (true) {
			try {
				OutputStream os = socket.getOutputStream();
				// BufferedReader br = new BufferedReader(new
				// InputStreamReader(is));
				InputStream is = socket.getInputStream();
				String msg = "欢迎登陆聊天室!\r\n";
				os.write(msg.getBytes());

				msg = "";
				while (!msg.equals("exit")) {
					int i = 0;
					StringBuffer strb = new StringBuffer();
					while ((i = is.read()) != 13) {//
						// 读取客户机发送过来的消息,只要不是13就继续读取,如果是13则结束
						strb.append((char) i);
					}
					is.read();// 读取换行符,丢掉
					msg = strb.toString();
					// msg = br.readLine();
					System.out.println("客户机说:" + msg);
					os.write(("服务器说:" + msg + "\r\n").getBytes());
				}
				os.close();
				socket.close();

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

      
           

在服务器创建中我们使用while(true){}循环确保服务器不会停止,一直处于阻塞状态中等待连接进来的客户机。ClientDemo类继承了线程,在run方法中创建客户机对象,初始化IO流。这样我们就可以生成多个客户端从而实现聊天功能。在这个基础上可以逐步加深,实现群聊功能,私聊,写自己设计的界面,制定通信协议以实现诸多功能。