`
吖龙Sam
  • 浏览: 21000 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java中的Socket编程(4)-实例

    博客分类:
  • Java
阅读更多

纸上得来终觉浅,绝知此事要躬行。—陆游
意思是说,从书本上得来的知识终归是浅薄的,要透彻的认知事务还必须亲自实践。
这句话告诉我们,除了要掌握好理论知识,还必须得亲自动手做实践,来证明结论。理论引导实践,实践推翻理论。正是这个道理!

前面三章,我们对Socket编程进行了一个比较全面的阐述,相信大家对Socket编程有了一个比较全面的认识,今天我们来实现一个实例,加深对Socket编程的理解。

1、实例:实现一个质数判断程序。即
客户端在控制台输入一个数字,服务端告诉客户端该数字是否是质数。

1)服务端程序流程:
(1)获取客户端输入的数据
(2)做判断处理
(3)返回处理结果

2)客户端程序流程:
(1)用户在控制台输入数字
(2)获取用户输入的数字并发送给服务端
(3)获取服务端响应结果,并输出在控制台中

3)说明:
(1)质数(素数):除了1和本身,没有其他公约数
(2)为节省流量,服务端程序不直接告诉客户端结果,而是通过规定的协议,返回状态码。
协议规定为(这个协议自己任意定):0 是质数, 1 不是质数, 2 输入非法

2、代码实现:

1)服务端代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 服务端:判断客户端输入的数字是否是质数
 * 步骤:
 * 1.获取客户端输入的数据
 * 2.做判断处理
 * 3.返回处理结果
 * 
 * @author Sam
 *
 */
public class PrimeNumServer {
	
	// 服务端监听的端口号
	private static final int PORT = 10000;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			ServerSocket ss = new ServerSocket(PORT);
			System.out.println("Server 等待客户端接入...");
			while (true) {
				// 监听客户端请求
				Socket socket = ss.accept();
				// 监听到有客户端接入,则开启一个子线程处理请求
				new Thread(new Task(socket)).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 处理Socket请求任务类
	 *
	 */
	private static class Task implements Runnable {
		
		private Socket socket;
		private BufferedReader buffRreader;
		private BufferedWriter buffWriter;
		
		public Task(Socket socket) {
			try {
				this.socket = socket;
				// 字符读取流
				this.buffRreader = new BufferedReader(
						new InputStreamReader(socket.getInputStream()));
				// 字符写入流
				this.buffWriter = new BufferedWriter(
						new OutputStreamWriter(socket.getOutputStream()));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void run() {
			handlRequest();
		}

		/**
		 * 处理请求
		 */
		private void handlRequest() {
			try {
				// 接收客户端数据
				String data = receive();
				// 处理逻辑
				String result = checkIsPrimeNum(data);
				// 发送响应结果
				send(result);
			} finally {
				StreamUtils.close(buffRreader, buffWriter);
				close(socket);
			}
		}

		/**
		 * 检查是否是质数,根据协议规定,返回状态码
		 * @param numStr
		 * @return 0 是质数, 1 不是质数, 2 输入非法
		 */
		private String checkIsPrimeNum(String numStr) {
			// 先判断输入的是否是数字
			boolean isNumber = isNumber(numStr);
			// 是数字,进一步判断是否是质数(素数)
			if (isNumber) {
				int number = Integer.parseInt(numStr);
				return isPrimeNumber(number);
				
			} else {// 输入非数字,则认为是非法的
				return "2";
			}
		}

		/**
		 * 判断是否是数字
		 * @param numStr
		 * @return
		 */
		private boolean isNumber(String numStr) {
			Pattern pattern = Pattern.compile("[0-9]*");
			Matcher matcher = pattern.matcher(numStr);
			return matcher.matches();
		}
		
		/**
		 * 判断是否是质数
		 * @param number
		 * @return 0 是质数, 1 不是质数, 2 输入非法
		 */
		private String isPrimeNumber(int number) {
			if (number < 2) {// 如果数字小于2,则认为是非法
				return "2";
			} else {
				// 真正做质数的判断逻辑
				for (int i=2; i<=number-1; i++) {
					/*
					 * 用2至number-1之间的所有数去整除number,
					 * 如果有一个能被整除,说明是number非质数
					 */
					if (number % i == 0) {
						return "1";
					}
				}
				return "0";
			}
		}

		/**
		 * 接收客户端发送过来的数据
		 * @return
		 */
		private String receive() {
			try {
				return buffRreader.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		/**
		 * 向客户端发送响应结果
		 * @param result
		 */
		private void send(String result) {
			try {
				buffWriter.write(result);
				buffWriter.newLine();// 写一个换行符
				buffWriter.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	/**
	 * 关闭客户端Socket
	 * @param socket
	 */
	private static void close(Socket socket) {
		if (socket != null) {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			socket = null;
		}
	}

}


服务端代码分析:
1、在isNumber(String numStr)方法中判断一个字符串是否是数字,用了一个正则匹配,匹配规则为:字符串是由0~9之间的数组成,并且可以出现零次或多次;有关更详细的匹配规则可以参看JDK文档中的:java.util.regex.Pattern类
2、在isPrimeNumber(int number)方法中判断一个数是否是质数:
用2至number-1之间的所有数去整除number,
1)如果有一个能被整除说明是number非质数;
2)如果所有的数都不未来整除,则说明是质数。
3、为了避免代码冗余,在finally子句中使用了一个StreamUtils流工具类来关闭资源,最后会把这个工具类的代码贴上。

2)客户端代码:

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

/**
 * 客户端:输入一个数字
 * 步骤:
 * 1.用户在控制台输入数字
 * 2.获取用户输入的数字并发送给服务端
 * 3.获取服务端响应结果
 * 
 * @author Sam
 *
 */
public class PrimeNumClient {
	
	// 主机
	private static final String HOST = "127.0.0.1";
	// 端口号
	private static final int PORT = 10000;

	private static Socket socket;
	private static BufferedReader buffReader;
	private static BufferedWriter buffWriter;
	
	private static BufferedReader keyboardReader;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			init();
			System.out.println("请在下面输入质数:");
			// 获取键盘输入流
			keyboardReader = new BufferedReader(new InputStreamReader(System.in));
			// 发送数据
			send(keyboardReader.readLine());
			// 接收响应结果
			String result = receive();
			// 处理结果
			handleResult(result);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {// 释放资源
			StreamUtils.close(buffReader, buffWriter);
			StreamUtils.close(keyboardReader);
			close(socket);
		}
	}

	/**
	 * 初始化操作
	 */
	private static void init() {
		try {
			// 连接到指定的主机与端口号的服务器上
			socket = new Socket(HOST, PORT);
			InputStream in = socket.getInputStream();
			OutputStream out = socket.getOutputStream();
			
			buffReader = new BufferedReader(new InputStreamReader(in));
			buffWriter = new BufferedWriter(new OutputStreamWriter(out));
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 向服务端发送数据
	 * @param data
	 */
	private static void send(String data) {
		try {
			buffWriter.write(data);
			buffWriter.newLine();// 写一个换行符
			buffWriter.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 接收服务端响应结果
	 * @return
	 */
	private static String receive() {
		try {
			return buffReader.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 处理服务端返回的结果
	 */
	private static void handleResult(String result) {
		
		if ("0".equals(result)) {// 是质数
			System.out.println("您输入的是质数");
			
		} else if ("1".equals(result)) {// 不是质数
			System.out.println("您输入的不是质数");
			
		} else if ("2".equals(result)) { // 输入非法
			System.out.println("警告!您输入非法!");
			
		}
	}
	
	/**
	 * 关闭客户端Socket
	 * @param socket
	 */
	private static void close(Socket socket) {
		if (socket != null) {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			socket = null;
		}
	}
	
}


客户端代码分析:
1、获取用户输入的数据,往服务端写数据时,一定要记得用newLine()方法写一个换行符,否则服务端一直处于读取状态,不会停止,因为读不到结束符;同理,服务端在往客户端写入响应结果时,也要用newLine()方法写一个换行符,否则客户端也会一直处于阻塞状态;
2、获取服务端返回的响应结果,根据之前规定的协议,在控制台中输出相应的提示信息。

3)IO流工具类StreamUtils代码:


import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

/**
 * IO流工具
 * @author Sam
 *
 */
public class StreamUtils {

	/**
	 * 同时关闭字符读取流与字符写入流
	 * @param reader
	 * @param writer
	 */
	public static void close(Reader reader, Writer writer) {
		close(reader);
		close(writer);
	}
	
	/**
	 * 关闭字符读取流
	 * @param reader
	 */
	public static void close(Reader reader) {
		if (reader != null) {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			reader = null;// 置空
		}
	}
	
	/**
	 * 关闭字符写入流
	 * @param writer
	 */
	public static void close(Writer writer) {
		if (writer != null) {
			try {
				writer.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			writer = null;// 置空
		}
	}
}


IO流工具类代码分析:
一般操作中,比较常用的,而且代码变动不大的,我们都会封装成一个工具类,以后直接使用,而不用重复的写。既避免代码冗余,又提高工作效率。

3、运行结果:
注意:先运行Server程序,再运行Client程序。为了测试结果,多次运行Client程序,并输入不同的数据,得到不同的提示信息。

1)Server程序控制台:


2)Client程序控制台
(1)运行第1次:



(2)运行第2次:



(3)运行第3次:



(4)运行第4次:



4、总结:
程序代码的逻辑并不复杂,但是基本做到了代码结构化。每个功能点都封装成一个方法,不同的业务放在不同的代码块中。这样以后要是某个模块出现了问题,就找相应的模块修改,而不被其他逻辑所干扰;实际开始中,也应该是这种思想。
  • 大小: 5.3 KB
  • 大小: 6.5 KB
  • 大小: 6.9 KB
  • 大小: 6.9 KB
  • 大小: 7.3 KB
分享到:
评论

相关推荐

    Java网络编程(socket---网上广播).rar_Java 网络_Socket网络编程_java socket _ja

    本教程将深入探讨Java中的Socket编程,特别是如何实现网上广播功能。网上广播允许一个设备向网络上的所有设备发送数据,无需预先知道接收者的具体地址。 首先,让我们了解什么是Socket。Socket在计算机网络中是一种...

    java-socket连接nodejs-socket

    Socket编程是一种基础的网络通信机制,允许两个应用程序通过网络交换数据。 首先,让我们深入了解一下Java中的Socket。在Java中,Socket是`java.net.Socket`类的一个实例,它代表了TCP协议中的一个连接。创建Socket...

    java socket编程实例(出自《java大学教程》)

    学习这些Java Socket编程实例,有助于理解TCP/IP通信的基本原理,为构建实际的网络应用程序打下坚实的基础。你可以通过调试和修改`SocketTest`代码,进一步探索和实践Socket编程的不同场景,如文件传输、聊天应用等...

    java socket 编程,Java socket 编程实例

    #### 三、Java中的Socket编程实例 接下来,我们通过一个简单的Java Socket编程示例来深入了解如何在Java中实现Socket编程。该示例展示了一个简单的Web客户端程序,用于获取一个HTML页面的内容。 ```java import ...

    java的Socket编程

    在Java中,`java.net.Socket`和`java.net.ServerSocket`类是Socket编程的主要工具。 1. **Socket类**: - `Socket`类代表TCP连接的一端,用于建立客户端与服务器之间的连接。它的构造函数通常需要指定服务器的IP...

    Java Socket网络编程.pdf

    在Java中,Socket编程主要涉及两个关键类:`ServerSocket`和`Socket`。`ServerSocket`类用于服务器端,它监听指定端口的连接请求。创建一个`ServerSocket`实例,例如`ServerSocket server = new ServerSocket(9998);...

    JAVA Socket编程实现文件上传

    Java Socket编程是网络编程的基础,它提供了在两个应用程序之间建立通信连接的能力。在这个场景中,我们讨论的是如何使用Java的Socket来实现文件上传功能,即从客户端将文件发送到服务器,然后保存到服务器的数据库...

    java socket编程

    Java Socket编程是Java平台中用于实现网络通信的核心API,它基于TCP/IP协议栈,提供了低级别的、面向连接的、可靠的字节流通信。在本文中,我们将深入探讨Java Socket编程的关键概念、工作原理以及如何创建服务端和...

    三步学会Java_Socket编程

    在Java中,Socket编程是实现网络通信的基础,它提供了进程间通信的能力,使得两个相隔万里的计算机可以通过互联网进行数据交换。本篇文章将深入讲解如何通过三步学习Java Socket编程。 **第一步:理解Socket** ...

    Java socket编程实例.pdf

    本文将通过一个具体的Java Socket编程实例来深入探讨如何使用Java实现客户端与服务端之间的通信。 #### 二、基础知识概述 在开始具体实例之前,我们需要了解一些基本概念: - **Socket**:Socket是一种用于在网络...

    java-socket传输文件-图片-源码

    在Java中,Socket API提供了丰富的类库支持,使得开发人员能够轻松实现网络编程。 - **客户端Socket**:用于发起连接请求,与服务端建立连接。 - **服务端Socket**:用于监听客户端的连接请求,并接收或发送数据。 ...

    java之socket编程简单实例

    这个简单的Java Socket编程实例展示了如何使用Java的网络API来实现客户端和服务器之间的通信。在实际应用中,可能会涉及到更复杂的逻辑,如解析HTTP请求,处理多线程并发连接,以及数据的编码和解码等。在压缩包文件...

    精通JAVA_SOCKET编程技术

    在深入理解JAVA_SOCKET编程技术之前,我们首先需要明确Socket的基本概念及其在Java中的应用。Socket,即套接字,是网络通信的基础,它提供了一种在网络中进行数据交换的方式,使不同计算机上的进程能够通过TCP/IP...

    Java面试之Socket编程

    在Java面试中,对Socket编程的理解和应用能力通常是评估开发者技能的重要标准。以下是对Socket编程的详细阐述: 1. **Java Socket编程基础** - Java中的Socket是网络通信的基础,它提供了两台计算机之间低级别的...

    Java源码:Socket编程.rar_java socket _java编程_socket java_socket编程 jav

    Java Socket编程是网络编程中的重要组成部分,主要用于实现客户端与服务器之间的通信。在Java中,Socket是基于TCP协议的,提供了一种可靠的、基于字节流的双向通信方式。本资料包含的"Java源码:Socket编程"是一个...

    Java socket编程实例代码(Blog配套代码)

    本实例代码是为了配合博客文章,提供一个简单的Java Socket聊天室的实现,帮助读者更好地理解和应用Socket编程。 在Java Socket编程中,主要有两个核心概念:服务器端(Server)和客户端(Client)。服务器端通过...

    Java网络socket编程详解

    Java网络socket编程是Java编程语言在网络编程中的一项核心技术,主要涉及到网络通信的两个基本概念:客户端(Client)和服务器(Server)。在Java中实现网络通信,主要依赖于Socket编程模型,尤其是基于TCP/IP协议的...

    java从入门到精通--实例

    8. **网络编程**:Java的Socket编程允许创建客户端和服务器应用程序,实现网络通信。理解TCP和UDP协议,以及套接字的使用,能让你构建网络应用。 9. **数据库操作**:JDBC(Java Database Connectivity)是连接Java...

    Java TCP IP Socket编程(原书第2版)

    《Java TCP/IP Socket编程》(原书第2版)是一本深入探讨Java中Socket编程的专著,旨在帮助读者理解并掌握如何在Java环境中利用TCP/IP协议进行网络通信。本书不仅详细介绍了Socket的工作原理,还提供了丰富的示例...

    Java网络编程-Socket-文件传输小案例

    在Java编程领域,网络编程是不可或缺的一部分,而Socket通信则是实现网络数据传输的基础。本案例主要探讨了如何使用Java的Socket API进行简单的文件传输。在这个过程中,我们将涉及到以下几个关键知识点: 1. **...

Global site tag (gtag.js) - Google Analytics