`
wandejun1012
  • 浏览: 2733385 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

socket 阻塞原因详解

    博客分类:
  • java
 
阅读更多

 

假设一个服务器程序,一个客户端程序。

 

根据课本上的知识,服务器程序代码如下:

 

package com.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static void main(String[] args) {
		new Server().run();
	}
	public void run(){
		try {
			ServerSocket serverSocket=new ServerSocket(9000);
			//得到客户端连接过来的socket
			Socket clientSocket=serverSocket.accept();
			System.out.println("有客户端上钩了");
			//拿到输入流
			BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
			//拿到输出流
			PrintWriter printWriter=new PrintWriter(clientSocket.getOutputStream());
			//拿到系统的输入流
			BufferedReader sysBufferedReader=new BufferedReader(new InputStreamReader(System.in));
			//在此就得打印一下从客服端收来的字符串
			System.out.println("client says:"+bufferedReader.readLine());//阻塞
			String contentFromSelf=sysBufferedReader.readLine();//阻塞
			System.out.println("服务器由于自身读键盘输入数据而卡住");
			while(!contentFromSelf.equals("bye")){
				//将自己说的话放进socket中推给客户端
				printWriter.println(contentFromSelf);
				//刷新,让客户端立即收到
				printWriter.flush();
				//将自己说的话显示在控制台
				System.out.println("server says:"+contentFromSelf);//阻塞
				//将客户端返回的话显示在下面
				System.out.println("client says:"+bufferedReader.readLine());//阻塞
				contentFromSelf=sysBufferedReader.readLine();
				//可以在这里打印一句话来测试readLine是否阻塞
			}
			clientSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

 

 

客户端代码如下:

 

package com.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Client {
	public static void main(String[] args) {
		new Client().run();
	}
	private void run(){
		try {
			Socket socket=new Socket("127.0.0.1",9000);
			//拿到输入流
			BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
			//拿到输入流
			PrintWriter printWriter=new PrintWriter(socket.getOutputStream());
			//拿到系统的输入流
			BufferedReader sysBufferedReader=new BufferedReader(new InputStreamReader(System.in));
			String contentFromSelf=sysBufferedReader.readLine();
			while(!contentFromSelf.equals("bye")){
				//将自己说的话放进socket中推给服务端
				printWriter.println(contentFromSelf);
				//刷新,让服务端立即收到
				printWriter.flush();
				//将自己说的话显示在控制台
				System.out.println("client says:"+contentFromSelf);
				//将服务器返回的话显示在下面
				System.out.println("server says:"+bufferedReader.readLine());
				//客户端读下一句话
				contentFromSelf=sysBufferedReader.readLine();
				//可以在这里打印一句话来测试readLine是否阻塞
			}
			
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

 

 

这样展现出来的效果是:

1.客户端必须发送第一句话,然后服务器端才能收到。

2.接下来是服务端必须发送一句话,客户端才能收到

3.接下来又是客户端一句话,服务端才能收到

…………

 

有点像网游里面的回合制,实在是落后了。

 

 

原因解析:下面的bufferedReader.readLine方法是阻塞的,是在读管道里面的值。

BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.println("client says:"+bufferedReader.readLine());//阻塞

 

另外,下面这句话是从标准的键盘里面输入值,此方法也是阻塞的。contentFromSelf=sysBufferedReader.readLine();

 

解决办法:

1.将发送的过程专门放在一个线程里

2.将接收的过程专门放在一个线程里

 

整个代码如下:

 

1.Server.java

package com.server;

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

import com.util.Receiver;
import com.util.Sender;

public class Server {
	public static void main(String[] args) {
		new Server().run();
	}

	public void run() {

		try {
			ServerSocket serverSocket = new ServerSocket(9000);

			// 得到客户端连接过来的socket
			Socket clientSocket = serverSocket.accept();

			System.out.println("有客户端上钩了");

			new Sender(clientSocket).start();

			new Receiver(clientSocket).start();

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

 

 

2.Client.java

package com.client;

import java.net.Socket;

import com.util.Receiver;
import com.util.Sender;

public class Client {

	public static void main(String[] args) {
		new Client().run();
	}

	private void run() {

		try {
			Socket socket = new Socket("127.0.0.1", 9000);
			new Sender(socket).start();

			new Receiver(socket).start();

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

 

3.Sender.java

package com.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Sender extends Thread {
	private Socket socket;

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

	@Override
	public void run() {

		try {

			// 拿到输出流
			PrintWriter printWriter = new PrintWriter(socket.getOutputStream());

			// 拿到系统的输入流
			BufferedReader sysBufferedReader = new BufferedReader(
					new InputStreamReader(System.in));

			String contentFromSelf = sysBufferedReader.readLine();// 阻塞

			while (!contentFromSelf.equals("bye")) {
				// 将自己说的话放进socket中推给客户端
				printWriter.println(contentFromSelf);
				// 刷新,让客户端立即收到
				printWriter.flush();

				// 将自己说的话显示在控制台
				System.out.println("server says:" + contentFromSelf);// 阻塞

				contentFromSelf = sysBufferedReader.readLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

 

4.Receiver.java

package com.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Sender extends Thread {
	private Socket socket;

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

	@Override
	public void run() {

		try {

			// 拿到输出流
			PrintWriter printWriter = new PrintWriter(socket.getOutputStream());

			// 拿到系统的输入流
			BufferedReader sysBufferedReader = new BufferedReader(
					new InputStreamReader(System.in));

			String contentFromSelf = sysBufferedReader.readLine();// 阻塞

			while (!contentFromSelf.equals("bye")) {
				// 将自己说的话放进socket中推给客户端
				printWriter.println(contentFromSelf);
				// 刷新,让客户端立即收到
				printWriter.flush();

				// 将自己说的话显示在控制台
				System.out.println("server says:" + contentFromSelf);// 阻塞

				contentFromSelf = sysBufferedReader.readLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

 

 

 注意:此服务端客户端程序只适用于一对一自由聊天,不能一(Server)对多(Client)聊天。下期介绍。

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    socket 经典编程 详解 教程

    此外,Socket编程还涉及到阻塞和非阻塞模式、多路复用I/O,例如`select()`函数,可以同时监控多个Socket的状态,提高程序的并发能力。 在学习Socket编程时,建议动手实践编写简单的服务器和客户端程序,以加深理解...

    Linux的socket编程详解

    ### Linux的Socket编程详解 #### 一、网络中进程间通信机制 进程间通信(IPC, Inter-Process Communication)在单机系统中主要是通过管道、信号、消息队列等方式实现的。然而,当涉及到跨主机通信时,就需要解决...

    详解socket阻塞与非阻塞,同步与异步、I/O模型

    Socket编程中的阻塞与非阻塞、同步与异步是两个独立的概念,它们涉及的是不同层面的操作机制。这里我们将详细探讨这两个概念以及I/O模型。 首先,同步与异步是客户端(C端)调用服务端(S端)时的行为模式。同步...

    Java使用socket网络编程详解

    ### Java使用Socket网络编程详解 #### 一、引言 Socket是网络通信的基础,它使得不同计算机间的进程可以通过网络进行通信。本篇文章旨在详细介绍如何在Java中使用Socket进行网络编程,特别是TCP协议下的客户端与...

    Java语言Socket接口用法详解.doc

    `ServerSocket` 的核心方法是 `accept()`,它会阻塞直到有客户端发起连接请求。当请求到来时,`accept()` 方法会返回一个新的 `Socket` 对象,表示与客户端的连接。这个新的 `Socket` 对象可以用于读写数据。例如: ...

    Linux UDP socket 设置为的非阻塞模式与阻塞模式区别

    ### Linux UDP Socket 非阻塞模式与阻塞模式的区别详解 #### 一、引言 在进行网络编程时,我们经常会遇到阻塞模式与非阻塞模式的选择问题。这两种模式直接影响程序的运行效率和资源利用率。本文将详细介绍在Linux...

    Java网络socket编程详解1.docx

    此外,还可以使用NIO(非阻塞I/O)或异步Socket API来提高性能和并发性。 总之,Java中的Socket编程涉及到TCP/IP通信的基础,理解和掌握Socket编程对于开发网络应用程序至关重要。通过创建Socket和ServerSocket对象...

    有关Socket模型详解

    Socket模型详解 在计算机网络编程中,Socket是客户端和服务器之间通信的基本机制。本文将深入探讨Socket模型,特别是针对Windows平台的Socket I/O操作,包括阻塞模式、非阻塞模式以及五种常见的Socket I/O模型:...

    windows下socket通信代码

    例如,多线程处理多个客户端连接、非阻塞I/O模型、使用套接字选项等。同时,注意在项目结束时调用`WSACleanup()`释放Winsock资源。 在学习Socket编程时,应理解TCP/IP协议的基础知识,包括三次握手、四次挥手等概念...

    Java网络socket编程详解

    ### Java网络Socket编程详解 #### 一、引言 在当今互联网时代,网络通信成为软件开发中的重要组成部分,而Socket编程则是实现网络通信的核心技术之一。Socket编程允许不同计算机之间通过网络进行通信,无论是...

    cSharp-socket-class.zip_C# socket类_C# socket详解_C# socket 编程_c#

    4. **异步编程**:C# Socket类支持异步操作,如BeginConnect、BeginAccept、BeginSend和BeginReceive等,这些方法允许在不阻塞主线程的情况下进行网络通信,提高程序的响应性。 5. **异常处理**:在进行Socket编程...

    Java网络socket编程详解.doc

    ### Java网络Socket编程详解 #### 一、引言 在计算机网络编程中,Socket是一种用于在网络之间进行通信的协议和接口。它允许不同主机上的进程相互通信,是实现网络应用的重要工具之一。本篇文章将深入探讨Java中的...

    android各组件详解- Socket

    ### Android各组件详解—Socket #### 一、引言 Socket是计算机网络中进行通信的基础技术之一,在Android开发中有着广泛的应用。无论是简单的客户端-服务器通信还是复杂的分布式系统设计,Socket都是实现网络通信的...

    Socket模型c++版本详解

    ### Socket模型C++版本详解 #### 一、引言 Socket是网络编程中不可或缺的一部分,它使得不同计算机之间能够通过网络进行数据交换。在Windows环境下,实现Socket的主要库是Winsock,而C++作为一种强大的面向对象语言...

    C++socket编程详解

    在讨论C++ socket编程详解时,我们首先需要理解什么是socket。Socket是网络通信的基础,它提供了应用程序之间进行数据交换的端点,其行为类似于电话插座。在计算机网络中,一个socket可以是网络中两个程序间数据交换...

    python进阶之socket模块详解.pdf

    4. `recv()`:接收来自客户端的数据,指定缓冲区大小,如果未收到数据,会阻塞等待。 5. `send()`/`sendall()`:向客户端发送数据,`sendall()`确保数据完整发送,即使数据量超过单次发送的限制。 6. `close()`:...

    android 简明Socket通信实例

    这通常在异步任务或者IntentService中执行,以避免阻塞主线程。以下是一个简单的示例: ```java try { Socket socket = new Socket("服务器IP", 服务器端口号); } catch (IOException e) { e.printStackTrace(); ...

Global site tag (gtag.js) - Google Analytics