【JavaWeb学习】socket通信

ServerSocket用法详解

在B/S通信模式中,服务端需要创建监听特定端口的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显示设置连接请求队列的长度,当服务器运行时候,会监听多个客户的连接请求,当服务器端收到多个连接请求,操作系统会把这些连接请求存储到一个先进先出的队列中。许多操作系统限定了队列的最大长度,一般为50。

参数bindAddr,当主机有多个IP地址(多网卡)的时候,就需要显示指定那个IP地址。

上面有一个默认构造方法,它的作用是,允许服务器在绑定到特定的端口之前,先设置ServerSocket的一些选项,因为一旦服务器与特定的端口绑定,有些选项就不能再改变了。

例如,可以先设置ServerSocket的SO_REUSEADDR的选项为true,然后再把它与8888端口绑定

serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(8888));
serverSocket选项
  • SO_TIMEOUT:等待客户连接的超时时间
  • SO_REUSEADDR:表示是否允许重用服务器所绑定的地址,boolean
  • SO_RCVBUF:表示接受数据的缓冲区的大小

SO_TIMEOUT表示serverSocket的accept()方法等待客户端连接的超时时间,以毫秒为单位。如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_TIMEOUT的默认值。accept方法会一直阻塞直到有客户端连接,方法才返回,或者超出了超时时间,那么accept方法会抛出SocketTimeoutException.

SO_REUSEADDR=false,当serverSocket关闭时,如果网络上还有发送到这个ServerSocket的数据,这个ServerSocket不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据,然后再释放端口。许多服务器程序都使用固定的端口,当服务器关闭时,它的端口可能还会被占用一段时间.如果立刻释放端口,释放的端口可能会立刻连上新的应用程序,这样存活在网络中的TCP报文会与新的TCP连接报文冲突,造成数据冲突。需要耐心等待网络中老的TCP连接的活跃报文全部消失,2MSL时间可以满足要求,这里涉及到TCP的四次挥手。

单线程Socket实例

创建ServerSocket服务器

public class Server {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		ServerSocket serverSocket=new ServerSocket(8888);//监听8888端口
		while(true) {
			System.out.println("socket已连接,等待客户端请求...");
			Socket socket = serverSocket.accept();
			new WebAction(socket).service();//获取请求内容并响应
		}
	}
}

WebAction类用来获取请求的内容并响应给浏览器

public class WebAction {
	
	private Socket socket;
	
	private BufferedReader bufferedReader=null;
	
	private BufferedWriter bufferedWriter=null;

	public WebAction(Socket socket) {
		this.socket=socket;
	}

	public void service() {
		try {
			readRequest(socket);
			writeHtml(socket);
			close();
		} catch (IOException e) {
		}	
	}
	
	public void readRequest(Socket socket) throws IOException {
		StringBuffer sb=null;
		String temp=null;
		bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//读取请求的内容
		sb=new StringBuffer();
        System.out.println("---------------------");
        while((temp=bufferedReader.readLine())!=null) {//注意这里,如果客户端不关闭,服务器就会一直等待
        	sb.append(temp);
        	System.out.println(temp);
        }
	}
	
	public void writeHtml(Socket socket) throws IOException {
		
		bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		StringBuffer sb=new StringBuffer();
		sb.append("http/1.1 200 ok").append("\n\n");
		sb.append("success");
		bufferedWriter.write(sb.toString());
		bufferedWriter.flush();
		bufferedWriter.close();
	}
	
	public void close() {
		try {
			bufferedReader.close();
			bufferedWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

启动服务器,并在浏览器中输入 http://localhost:8888/app?name=zhangsan ,发现请求的内容服务器已经获取到了
在这里插入图片描述
但是浏览器一直在等待,这是怎么回事呢
在这里插入图片描述
原来如果客户端打开一个输入流,如果不做约定,也不关闭它,那么服务端永远不知道客户端是否发送完消息,那么服务端就会一直等待下去,直到读取超时。所以怎么告诉服务端已经发送完消息就很重要。

socket判断发送完成的方式
  • 方法一:Socket关闭,当socket关闭,服务端会接收到响应的关闭信号,那么服务端就知道流已经关闭了,这个时候读操作完成。但是这种方法太暴力,而且socket关闭后,客户端将不能接收服务器发送的消息,也不能再次发送消息了。如果客户端想再次发送消息,需要重新创建Socket连接。

  • 方法二:客户端发送完成后,调用socket.shutdownOutput()而不是

outputStream.close() //如果关闭了输出流,那么相应的socket也会关闭,和直接调用socket.close是一样的。

这种方法优点是发送完成之后可以接收服务端返回的数据,缺点是也不能再次发送了。

  • 方法三:客户端与服务器约定符号

例如,客户端在发送消息的最后加上一个“end”标志,当服务端读取到该标志,就知道客户端已经发送完成了。但这种方法容易引起误操作。

  • 方法四:客户端指定长度

可以采用计算机界普遍采用的,先通过前面几个字节来说明后面跟随的消息的长度。例如0xxxxxxx

表示第一个字节表示内容的长度,内容最大是128个字节,即128B

话说回来,通过浏览器访问socket服务器,服务器如何知道发送结束了呢?因为浏览器采用的是http协议,HTTP请求包括了一下内容:一个请求行、若干个请求头、实体内容,以GET请求为例,请求格式如下图所示
在这里插入图片描述
从上图可知,get请求的最后会有一个空行,我们可以以此作为get请求发送结束的标志。

只要修改一行代码即可

	public void readRequest(Socket socket) throws IOException {
		StringBuffer sb=null;
		String temp=null;
		bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		sb=new StringBuffer();
        System.out.println("---------------------");
        while((temp=bufferedReader.readLine())!=null && !"".equals(temp)) {//判断get请求是否结束
        	sb.append(temp);
        	System.out.println(temp);
        }
	}

但是上面的例子是单线程的,如果同时有多个请求,那只能排队等待,这显然不太合适,下面我们就改造成多线程的Socket服务器,每当有新的请求,就分配一个线程给该请求。

多线程服务器

为了让服务器能够同时为多个客户提供服务,提高服务器的并发能力,可以创建一个线程池,每次从线程池中取出工作线程为客户服务。

public class Server {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		ServerSocket serverSocket=new ServerSocket(8888);
		ExecutorService executorService = Executors.newCachedThreadPool();
		while(true) {
			System.out.println("socket已连接,等待客户端请求...");
			final Socket socket = serverSocket.accept();
			// 每个请求分配一个线程
			executorService.execute(new Runnable() {
				public void run() {
					new WebAction(socket).service();//获取请求内容并响应
				}
			});
		}
	}
}
参考文章

Java Socket变成基础及深入讲解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要实现JavaWeb中的串口通信,需要借助一些额外的工具和库。首先,需要使用Java提供的串口通信库,例如RXTX、JSerialComm等。其次,为了在JavaWeb中使用这些库,可以通过将它们作为依赖项添加到项目中。接下来,需要编写一些Java代码来实现串口通信的逻辑。 首先,需要初始化串口连接。可以通过获取串口的名称、波特率、数据位、停止位、校验位等参数来初始化串口。一旦成功初始化串口连接,就可以打开串口,准备进行数据的发送和接收。 在进行串口通信时,可以使用Java提供的输入输出流来实现数据的读取和写入。通过输入流,可以读取从串口接收到的数据;通过输出流,可以向串口发送数据。可以根据需要,在JavaWeb中编写逻辑来处理接收到的数据,例如将其展示在Web页面上或者进行其他处理。 为了保证串口通信的稳定性和可靠性,可以实现一些错误处理机制。例如,可以设置超时时间,在一定时间内没有接收到数据时,进行重连或者发送一些错误提示信息。另外,可以设置缓冲区来存储接收到的数据,以便进一步处理。 总之,要实现JavaWeb中的串口通信,需要使用串口通信库,并编写适当的Java代码来初始化、打开串口连接,以及进行数据的读写和处理。通过合理的逻辑和错误处理,可以实现稳定和可靠的串口通信功能。 ### 回答2: JavaWeb是一种用于开发Web应用程序的Java技术。而串口通信是通过串口来进行数据传输的一种通信方式。虽然JavaWeb主要用于Web开发,但是也可以通过一些第三方库或工具实现串口通信。 在Java中,实现串口通信可以使用RXTXComm库。首先,需要下载并引入该库,然后通过该库提供的API来进行串口通信的编程。 首先,需要使用SerialPort类来打开串口,并设置串口的通信参数,如波特率、数据位、停止位、校验位等。然后,可以使用InputStream和OutputStream进行数据的读写。读取串口数据可以通过InputStream的read方法,写入串口数据可以通过OutputStream的write方法。 另外,还可以使用Event来监听串口的数据变化。通过实现SerialPortEventListener接口,并注册监听器,可以在监听器中进行相应的处理操作。 除了RXTXComm库,还有一些其他的Java库也可以实现串口通信,如jSSC、JavaComm等。这些库都提供了类似的API,可以方便地实现串口通信功能。 总结一下,要实现JavaWeb中的串口通信,可以使用一些第三方库或工具,如RXTXComm、jSSC、JavaComm等。通过这些库提供的API,可以打开串口、设置串口参数、读写串口数据,并通过监听器监听串口的数据变化。这样就可以在JavaWeb中实现串口通信的功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值