使用socket写一个简单的聊天程序&碰到的问题

程序分成2个部分:

1,服务端,用来接受客户端发来的信息

2,客户端,用来向服务端发信息。

一、服务端如下:

SocketServerThread.java用来处理客户端发送的信息

package com.thread.socket.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class SocketServerThread extends Thread {
	
	// 和本线程相关的Socket
	Socket socket = null;
	
	public SocketServerThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		OutputStream os = null;
		PrintWriter pw = null;
		//获取输入流,并读取客户端信息
		try {
			is = socket.getInputStream();
			isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			String info = null;
			while((info=br.readLine()) != null) { //循环读取客户端的信息
				System.out.println(info);
			}
			socket.shutdownInput(); //关闭输入流
			// 获取输出流,响应客户端的请求
			os = socket.getOutputStream();
			pw = new PrintWriter(os);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//关闭资源
            try {
            	if(pw!=null) pw.close();
            	if(os!=null) os.close();
            	if(br!=null) br.close();
            	if(isr!=null) isr.close();
            	if(is!=null) is.close();
            	if(socket!=null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
		}
	}
}

ServerThread.java用来监听客户端请求,接受请求后开启线程调度SocketServerThread.java

package com.thread.socket.service;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 用来接受客户端发送的信息
 *
 */
public class ServerThread extends Thread {

	@SuppressWarnings("resource")
	@Override
	public void run() {
		// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
		try {
			ServerSocket serverSocket = new ServerSocket(8888);
			Socket socket = null;
			System.out.println("***服务器即将启动,等待客户端的连接***");
			// 循环监听等待客户端的连接
			while(true) {
				// 调用accept()方法开始监听,等待客户端的连接
				socket = serverSocket.accept();
				// 创建一个新的线程,用来处理请求
				SocketServerThread serverThread = new SocketServerThread(socket);
				// 启动线程
				serverThread.start();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

二、客户端如下:

Client.java

package com.thread.socket.client;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

	/**
	 * 向服务端发送信息
	 * 
	 * @param str
	 */
	public static void output(String str) {
		try {
			// 1.创建客户端Socket,指定服务器地址和端口
			Socket socket = new Socket("localhost", 8008); // TODO 这里用的是本地的IP
			// 2.获取输出流,向服务器端发送信息
			OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);
			pw.write(str);
			pw.flush();
			socket.shutdownOutput();//关闭输出流
			//4.关闭资源
			pw.close();
			os.close();
			socket.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

三、启动服务端

package com.thread.socket.main;

import java.util.Scanner;
import com.thread.socket.client.Client;
import com.thread.socket.service.ServerThread;

public class Chat {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		// 启动服务器
		ServerThread s = new ServerThread();
		s.start();
		// 向服务器发送信息
		while (true) {
			Scanner sb = new Scanner(System.in);  
			System.out.print("输入语句:");  
			String str = sb.nextLine();
			Client.output(str);
		}
	}
}

注意:上面几个文件放在一起算一个程序。

将上述文件复制一份,做成另一个程序,开启这两个程序,就可以相互聊天了。

如果想在本地让这两程序相互发送消息的话,其中的一个程序的服务端要需要修改监听端口号,

另外一个程序的客户端要更改发送的端口号,这样两个程序才能在本地相互发送消息;

否则启动好一个程序后,再启动另一个程序,就会报该端口号被占用的错误。

---------------------------下面是本人搞事时,发现的bug-----------------------------

另外本人尝试连续不断的向服务端发送10000的请求,发现报错了

注意:设置成10000时,有时候会报错,不一定是每次都报错,如果想每次报错把这个10000改成100w试试。

报错信息如下:java.net.BindException: Address already in use: connect

这是别人的解释:https://blog.csdn.net/ywb201314/article/details/51258777

大致原因是端口号来不及释放,导致错误。

------------------------------------------------------------------------------------------

我多次测试之后,感觉应该是服务端接受请求上限导致的。

测试结果:服务端同时能接受的请求的上限是50条,

ServerSocket类部分源码定义如下(大概在229行左右):

public ServerSocket(int port) throws IOException {
    this(port, 50, null);
}

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
    setImpl();
    if (port < 0 || port > 0xFFFF)
        throw new IllegalArgumentException(
                   "Port value out of range: " + port);
    if (backlog < 1)
      backlog = 50;
    try {
        bind(new InetSocketAddress(bindAddr, port), backlog);
    } catch(SecurityException e) {
        close();
        throw e;
    } catch(IOException e) {
        close();
        throw e;
    }
}

backlog这个参数解释是:请求链接队列的最大长度。

当你直接 new ServerSocket(port)时,默认是50。

从上面构造可以看出请求链接最大不能超过0xFFFF=2^16-1=65535


猜你喜欢

转载自blog.csdn.net/h996666/article/details/80405200