假设一个服务器程序,一个客户端程序。
根据课本上的知识,服务器程序代码如下:
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编程还涉及到阻塞和非阻塞模式、多路复用I/O,例如`select()`函数,可以同时监控多个Socket的状态,提高程序的并发能力。 在学习Socket编程时,建议动手实践编写简单的服务器和客户端程序,以加深理解...
### Linux的Socket编程详解 #### 一、网络中进程间通信机制 进程间通信(IPC, Inter-Process Communication)在单机系统中主要是通过管道、信号、消息队列等方式实现的。然而,当涉及到跨主机通信时,就需要解决...
Socket编程中的阻塞与非阻塞、同步与异步是两个独立的概念,它们涉及的是不同层面的操作机制。这里我们将详细探讨这两个概念以及I/O模型。 首先,同步与异步是客户端(C端)调用服务端(S端)时的行为模式。同步...
### Java使用Socket网络编程详解 #### 一、引言 Socket是网络通信的基础,它使得不同计算机间的进程可以通过网络进行通信。本篇文章旨在详细介绍如何在Java中使用Socket进行网络编程,特别是TCP协议下的客户端与...
`ServerSocket` 的核心方法是 `accept()`,它会阻塞直到有客户端发起连接请求。当请求到来时,`accept()` 方法会返回一个新的 `Socket` 对象,表示与客户端的连接。这个新的 `Socket` 对象可以用于读写数据。例如: ...
### Linux UDP Socket 非阻塞模式与阻塞模式的区别详解 #### 一、引言 在进行网络编程时,我们经常会遇到阻塞模式与非阻塞模式的选择问题。这两种模式直接影响程序的运行效率和资源利用率。本文将详细介绍在Linux...
此外,还可以使用NIO(非阻塞I/O)或异步Socket API来提高性能和并发性。 总之,Java中的Socket编程涉及到TCP/IP通信的基础,理解和掌握Socket编程对于开发网络应用程序至关重要。通过创建Socket和ServerSocket对象...
Socket模型详解 在计算机网络编程中,Socket是客户端和服务器之间通信的基本机制。本文将深入探讨Socket模型,特别是针对Windows平台的Socket I/O操作,包括阻塞模式、非阻塞模式以及五种常见的Socket I/O模型:...
例如,多线程处理多个客户端连接、非阻塞I/O模型、使用套接字选项等。同时,注意在项目结束时调用`WSACleanup()`释放Winsock资源。 在学习Socket编程时,应理解TCP/IP协议的基础知识,包括三次握手、四次挥手等概念...
### Java网络Socket编程详解 #### 一、引言 在当今互联网时代,网络通信成为软件开发中的重要组成部分,而Socket编程则是实现网络通信的核心技术之一。Socket编程允许不同计算机之间通过网络进行通信,无论是...
4. **异步编程**:C# Socket类支持异步操作,如BeginConnect、BeginAccept、BeginSend和BeginReceive等,这些方法允许在不阻塞主线程的情况下进行网络通信,提高程序的响应性。 5. **异常处理**:在进行Socket编程...
### Java网络Socket编程详解 #### 一、引言 在计算机网络编程中,Socket是一种用于在网络之间进行通信的协议和接口。它允许不同主机上的进程相互通信,是实现网络应用的重要工具之一。本篇文章将深入探讨Java中的...
### Android各组件详解—Socket #### 一、引言 Socket是计算机网络中进行通信的基础技术之一,在Android开发中有着广泛的应用。无论是简单的客户端-服务器通信还是复杂的分布式系统设计,Socket都是实现网络通信的...
### Socket模型C++版本详解 #### 一、引言 Socket是网络编程中不可或缺的一部分,它使得不同计算机之间能够通过网络进行数据交换。在Windows环境下,实现Socket的主要库是Winsock,而C++作为一种强大的面向对象语言...
在讨论C++ socket编程详解时,我们首先需要理解什么是socket。Socket是网络通信的基础,它提供了应用程序之间进行数据交换的端点,其行为类似于电话插座。在计算机网络中,一个socket可以是网络中两个程序间数据交换...
4. `recv()`:接收来自客户端的数据,指定缓冲区大小,如果未收到数据,会阻塞等待。 5. `send()`/`sendall()`:向客户端发送数据,`sendall()`确保数据完整发送,即使数据量超过单次发送的限制。 6. `close()`:...
这通常在异步任务或者IntentService中执行,以避免阻塞主线程。以下是一个简单的示例: ```java try { Socket socket = new Socket("服务器IP", 服务器端口号); } catch (IOException e) { e.printStackTrace(); ...