[转]C#网络编程(同步传输字符串) - Part.2

本文转自:http://www.tracefact.net/CSharp-Programming/Network-Programming-Part2.aspx

服务端客户端通信

在与服务端的连接建立以后,我们就可以通过此连接来发送和接收数据。端口与端口之间以流(Stream)的形式传输数据,因为几乎任何对象都可以保存到流中,所以实际上可以在客户端与服务端之间传输任何类型的数据。对客户端来说,往流中写入数据,即为向服务器传送数据;从流中读取数据,即为从服务端接收数据。对服务端来说,往流中写入数据,即为向客户端发送数据;从流中读取数据,即为从客户端接收数据。

同步传输字符串

1.客户端发送,服务端接收并输出1.1服务端程序我们可以在TcpClient上调用GetStream()方法来获得连接到远程计算机的流。注意这里我用了远程这个词,当在客户端调用时,它得到连接服务端的流;当在服务端调用时,它获得连接客户端的流。接下来我们来看一下代码,我们先看服务端(注意这里没有使用do/while循环):class Server {static void Main(string[] args) {const int BufferSize = 8192;    // 缓存大小,8192字节
                    Console.WriteLine("Server is running ... ");IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });TcpListener listener = new TcpListener(ip, 8500);listener.Start();           // 开始侦听Console.WriteLine("Start Listening ...");// 获取一个连接,中断方法TcpClient remoteClient = listener.AcceptTcpClient();// 打印连接到的客户端信息Console.WriteLine("Client Connected!{0} <-- {1}",remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);// 获得流,并写入buffer中NetworkStream streamToClient = remoteClient.GetStream();byte[] buffer = new byte[BufferSize];int bytesRead = streamToClient.Read(buffer, 0, BufferSize);Console.WriteLine("Reading data, {0} bytes ...", bytesRead);// 获得请求的字符串string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);Console.WriteLine("Received: {0}", msg);// 按Q退出
    }}这段程序的上半部分已经很熟悉了,我就不再解释。remoteClient.GetStream()方法获取到了连接至客户端的流,然后从流中读出数据并保存在了buffer缓存中,随后使用Encoding.Unicode.GetString()方法,从缓存中获取到了实际的字符串。最后将字符串打印在了控制台上。这段代码有个地方需要注意:在能够读取的字符串的总字节数大于BufferSize的时候会出现字符串截断现象,因为缓存中的数目总是有限的,而对于大对象,比如说图片或者其它文件来说,则必须采用“分次读取然后转存”这种方式,比如这样:// 获取字符串
byte[] buffer = new byte[BufferSize];
int bytesRead;          // 读取的字节数
MemoryStream msStream = new MemoryStream();
do {bytesRead = streamToClient.Read(buffer, 0, BufferSize);msStream.Write(buffer, 0, bytesRead);} while (bytesRead > 0);buffer = msStream.GetBuffer();
string msg = Encoding.Unicode.GetString(buffer);这里我没有使用这种方法,一个是因为不想关注在太多的细节上面,一个是因为对于字符串来说,8192字节已经很多了,我们通常不会传递这么多的文本。当使用Unicode编码时,8192字节可以保存4096个汉字和英文字符。使用不同的编码方式,占用的字节数有很大的差异,在本文最后面,有一段小程序,可以用来测试Unicode、UTF8、ASCII三种常用编码方式对字符串编码时,占用的字节数大小。现在对客户端不做任何修改,然后运行先运行服务端,再运行客户端。结果我们会发现这样一件事:服务端再打印完“Client Connected!127.0.0.1:8500 <-- 127.0.0.1:xxxxx”之后,再次被阻塞了,而没有输出“Reading data, {0} bytes ...”。可见,与AcceptTcpClient()方法类似,这个Read()方法也是同步的,只有当客户端发送数据的时候,服务端才会读取数据、运行此方法,否则它便会一直等待。1.2 客户端程序接下来我们编写客户端向服务器发送字符串的代码,与服务端类似,它先获取连接服务器端的流,将字符串保存到buffer缓存中,再将缓存写入流,写入流这一过程,相当于将消息发往服务端。class Client {static void Main(string[] args) {Console.WriteLine("Client Running ...");TcpClient client;try {client = new TcpClient();client.Connect("localhost", 8500);      // 与服务器连接} catch (Exception ex) {Console.WriteLine(ex.Message);return;}// 打印连接到的服务端信息Console.WriteLine("Server Connected!{0} --> {1}",client.Client.LocalEndPoint, client.Client.RemoteEndPoint);string msg = "\"Welcome To TraceFact.Net\"";NetworkStream streamToServer = client.GetStream();byte[] buffer = Encoding.Unicode.GetBytes(msg);     // 获得缓存streamToServer.Write(buffer, 0, buffer.Length);     // 发往服务器Console.WriteLine("Sent: {0}", msg);// 按Q退出
    }}现在再次运行程序,得到的输出为:// 服务端
Server is running ...Start Listening ...Client Connected!127.0.0.1:8500 <-- 127.0.0.1:7847Reading data, 52 bytes ...Received: "Welcome To TraceFact.Net"
输入"Q"键退出。
// 客户端
Client Running ...Server Connected!127.0.0.1:7847 --> 127.0.0.1:8500Sent: "Welcome To TraceFact.Net"
输入"Q"键退出。再继续进行之前,我们假设客户端可以发送多条消息,而服务端要不断的接收来自客户端发送的消息,但是上面的代码只能接收客户端发来的一条消息,因为它已经输出了“输入Q键退出”,说明程序已经执行完毕,无法再进行任何动作。此时如果我们再开启一个客户端,那么出现的情况是:客户端可以与服务器建立连接,也就是netstat-a显示为ESTABLISHED,这是操作系统所知道的;但是由于服务端的程序已经执行到了最后一步,只能输入Q键退出,无法再采取任何的动作。回想一个上面我们需要一个服务器对应多个客户端时,对AcceptTcpClient()方法的处理办法,将它放在了do/while循环中;类似地,当我们需要一个服务端对同一个客户端的多次请求服务时,可以将Read()方法放入到do/while循环中。现在,我们大致可以得出这样几个结论:
•如果不使用do/while循环,服务端只有一个listener.AcceptTcpClient()方法和一个TcpClient.GetStream().Read()方法,则服务端只能处理到同一客户端的一条请求。
•如果使用一个do/while循环,并将listener.AcceptTcpClient()方法和TcpClient.GetStream().Read()方法都放在这个循环以内,那么服务端将可以处理多个客户端的一条请求。
•如果使用一个do/while循环,并将listener.AcceptTcpClient()方法放在循环之外,将TcpClient.GetStream().Read()方法放在循环以内,那么服务端可以处理一个客户端的多条请求。
•如果使用两个do/while循环,对它们进行分别嵌套,那么结果是什么呢?结果并不是可以处理多个客户端的多条请求。因为里层的do/while循环总是在为一个客户端服务,因为它会中断在TcpClient.GetStream().Read()方法的位置,而无法执行完毕。即使可以通过某种方式让里层循环退出,比如客户端往服务端发去“exit”字符串时,服务端也只能挨个对客户端提供服务。如果服务端想执行多个客户端的多个请求,那么服务端就需要采用多线程。主线程,也就是执行外层do/while循环的线程,在收到一个TcpClient之后,必须将里层的do/while循环交给新线程去执行,然后主线程快速地重新回到listener.AcceptTcpClient()的位置,以响应其它的客户端。对于第四种情况,实际上是构建一个服务端更为通常的情况,所以需要专门开辟一个章节讨论,这里暂且放过。而我们上面所做的,即是列出的第一种情况,接下来我们再分别看一下第二种和第三种情况。对于第二种情况,我们按照上面的叙述先对服务端进行一下改动:do {// 获取一个连接,中断方法TcpClient remoteClient = listener.AcceptTcpClient();// 打印连接到的客户端信息Console.WriteLine("Client Connected!{0} <-- {1}",remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);// 获得流,并写入buffer中NetworkStream streamToClient = remoteClient.GetStream();byte[] buffer = new byte[BufferSize];int bytesRead = streamToClient.Read(buffer, 0, BufferSize);Console.WriteLine("Reading data, {0} bytes ...", bytesRead);// 获得请求的字符串string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);Console.WriteLine("Received: {0}", msg);} while (true);然后启动多个客户端,在服务端应该可以看到下面的输出(客户端没有变化):Server is running ...Start Listening ...Client Connected!127.0.0.1:8500 <-- 127.0.0.1:8196Reading data, 52 bytes ...Received: "Welcome To TraceFact.Net"Client Connected!127.0.0.1:8500 <-- 127.0.0.1:8199Reading data, 52 bytes ...Received: "Welcome To TraceFact.Net"由第2种情况改为第3种情况,只需要将do向下挪动几行就可以了:// 获取一个连接,中断方法
TcpClient remoteClient = listener.AcceptTcpClient();
// 打印连接到的客户端信息
Console.WriteLine("Client Connected!{0} <-- {1}",remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);
// 获得流,并写入buffer中
NetworkStream streamToClient = remoteClient.GetStream();do {byte[] buffer = new byte[BufferSize];int bytesRead = streamToClient.Read(buffer, 0, BufferSize);Console.WriteLine("Reading data, {0} bytes ...", bytesRead);// 获得请求的字符串string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);Console.WriteLine("Received: {0}", msg);} while (true);然后我们再改动一下客户端,让它发送多个请求。当我们按下S的时候,可以输入一行字符串,然后将这行字符串发送到服务端;当我们输入X的时候则退出循环:NetworkStream streamToServer = client.GetStream();
ConsoleKey key;
Console.WriteLine("Menu: S - Send, X - Exit");
do {key = Console.ReadKey(true).Key;if (key == ConsoleKey.S) {// 获取输入的字符串Console.Write("Input the message: ");string msg = Console.ReadLine();byte[] buffer = Encoding.Unicode.GetBytes(msg);     // 获得缓存streamToServer.Write(buffer, 0, buffer.Length);     // 发往服务器Console.WriteLine("Sent: {0}", msg);}} while (key != ConsoleKey.X);接下来我们先运行服务端,然后再运行客户端,输入一些字符串,来进行测试,应该能够看到下面的输出结果:// 服务端
Server is running ...Start Listening ...Client Connected!127.0.0.1:8500 <-- 127.0.0.1:11004Reading data, 44 bytes ...Received: 欢迎访问我的博客:TraceFact.Net
Reading data, 14 bytes ...Received: 我们一起进步!
//客户端
Client Running ...Server Connected!127.0.0.1:11004 --> 127.0.0.1:8500Menu: S - Send, X - ExitInput the message: 欢迎访问我的博客:TraceFact.NetSent: 欢迎访问我的博客:TraceFact.NetInput the message: 我们一起进步!
Sent: 我们一起进步!这里还需要注意一点,当客户端在TcpClient实例上调用Close()方法,或者在流上调用Dispose()方法,服务端的streamToClient.Read()方法会持续地返回0,但是不抛出异常,所以会产生一个无限循环;而如果直接关闭掉客户端,或者客户端执行完毕但没有调用stream.Dispose()或者TcpClient.Close(),如果服务器端此时仍阻塞在Read()方法处,则会在服务器端抛出异常:“远程主机强制关闭了一个现有连接”。因此,我们将服务端的streamToClient.Read()方法需要写在一个try/catch中。同理,如果在服务端已经连接到客户端之后,服务端调用remoteClient.Close(),则客户端会得到异常“无法将数据写入传输连接: 您的主机中的软件放弃了一个已建立的连接。”;而如果服务端直接关闭程序的话,则客户端会得到异常“无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。”。因此,它们的读写操作必须都放入到try/catch块中。2.服务端回发,客户端接收并输出2.2服务端程序我们接着再进行进一步处理,服务端将收到的字符串改为大写,然后回发,客户端接收后打印。此时它们的角色和上面完全进行了一下对调:对于服务端来说,就好像刚才的客户端一样,将字符串写入到流中;而客户端则同服务端一样,接收并打印。除此以外,我们最好对流的读写操作加上lock,现在我们直接看代码,首先看服务端:class Server {static void Main(string[] args) {const int BufferSize = 8192;    // 缓存大小,8192Bytes
        ConsoleKey key;Console.WriteLine("Server is running ... ");IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });TcpListener listener = new TcpListener(ip, 8500);listener.Start();           // 开始侦听Console.WriteLine("Start Listening ...");// 获取一个连接,同步方法,在此处中断TcpClient remoteClient = listener.AcceptTcpClient();// 打印连接到的客户端信息Console.WriteLine("Client Connected!{0} <-- {1}",remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);// 获得流NetworkStream streamToClient = remoteClient.GetStream();do {// 写入buffer中byte[] buffer = new byte[BufferSize];int bytesRead;try {lock(streamToClient){bytesRead = streamToClient.Read(buffer, 0, BufferSize);}if (bytesRead == 0) throw new Exception("读取到0字节");Console.WriteLine("Reading data, {0} bytes ...", bytesRead);// 获得请求的字符串string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);Console.WriteLine("Received: {0}", msg);// 转换成大写并发送msg = msg.ToUpper();                    buffer = Encoding.Unicode.GetBytes(msg);lock(streamToClient){streamToClient.Write(buffer, 0, buffer.Length);}Console.WriteLine("Sent: {0}", msg);} catch (Exception ex) {Console.WriteLine(ex.Message);break;}                           } while (true);streamToClient.Dispose();remoteClient.Close();Console.WriteLine("\n\n输入\"Q\"键退出。");do {key = Console.ReadKey(true).Key;} while (key != ConsoleKey.Q);}}接下来是客户端:class Client {static void Main(string[] args) {Console.WriteLine("Client Running ...");TcpClient client;ConsoleKey key;const int BufferSize = 8192;try {client = new TcpClient();client.Connect("localhost", 8500);      // 与服务器连接} catch (Exception ex) {Console.WriteLine(ex.Message);return;}// 打印连接到的服务端信息Console.WriteLine("Server Connected!{0} --> {1}",client.Client.LocalEndPoint, client.Client.RemoteEndPoint);NetworkStream streamToServer = client.GetStream();          Console.WriteLine("Menu: S - Send, X - Exit");do {key = Console.ReadKey(true).Key;if (key == ConsoleKey.S) {// 获取输入的字符串Console.Write("Input the message: ");string msg = Console.ReadLine();byte[] buffer = Encoding.Unicode.GetBytes(msg);     // 获得缓存try {lock(streamToServer){streamToServer.Write(buffer, 0, buffer.Length);     // 发往服务器
                    }Console.WriteLine("Sent: {0}", msg);int bytesRead;buffer = new byte[BufferSize];                      lock(streamToServer){bytesRead = streamToServer.Read(buffer, 0, BufferSize);}msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);Console.WriteLine("Received: {0}", msg);} catch (Exception ex) {Console.WriteLine(ex.Message);break;}}} while (key != ConsoleKey.X);streamToServer.Dispose();client.Close();Console.WriteLine("\n\n输入\"Q\"键退出。");do {key = Console.ReadKey(true).Key;} while (key != ConsoleKey.Q);}}最后我们运行程序,然后输入一串英文字符串,然后看一下输出:// 客户端
Client is running ...Server Connected!127.0.0.1:12662 --> 127.0.0.1:8500Menu: S - Send, X - ExitInput the message: Hello, I'm jimmy zhang.Sent: Hello, I'm jimmy zhang.Received: HELLO, I'M JIMMY ZHANG.// 服务端
Server is running ...Start Listening ...Client Connected!127.0.0.1:8500 <-- 127.0.0.1:12662Reading data, 46 bytes ...Received: Hello, I'm jimmy zhang.Sent: HELLO, I'M JIMMY ZHANG.

看到这里,我想你应该对使用TcpClient和TcpListener进行C#网络编程有了一个初步的认识,可以说是刚刚入门了,后面的路还很长。本章的所有操作都是同步操作,像上面的代码也只是作为一个入门的范例,实际当中,一个服务端只能为一个客户端提供服务的情况是不存在的,下面就让我们来看看上面所说的第四种情况,如何进行异步的服务端编程。附录:ASCII、UTF8、Uncicode编码下的中英文字符大小private static void ShowCode() {string[] strArray = { "b", "abcd", "", "甲乙丙丁" };byte[] buffer;string mode, back;foreach (string str in strArray) {for (int i = 0; i <= 2; i++) {if (i == 0) {buffer = Encoding.ASCII.GetBytes(str);back = Encoding.ASCII.GetString(buffer, 0, buffer.Length);mode = "ASCII";} else if (i == 1) {buffer = Encoding.UTF8.GetBytes(str);back = Encoding.UTF8.GetString(buffer, 0, buffer.Length);mode = "UTF8";} else {buffer = Encoding.Unicode.GetBytes(str);back = Encoding.Unicode.GetString(buffer, 0, buffer.Length);mode = "Unicode";}Console.WriteLine("Mode: {0}, String: {1}, Buffer.Length: {2}",mode, str, buffer.Length);Console.WriteLine("Buffer:");for (int j = 0; j <= buffer.Length - 1; j++) {Console.Write(buffer[j] + " ");}Console.WriteLine("\nRetrived: {0}\n", back);}}}输出为:Mode: ASCII, String: b, Buffer.Length: 1Buffer: 98Retrived: bMode: UTF8, String: b, Buffer.Length: 1Buffer: 98Retrived: bMode: Unicode, String: b, Buffer.Length: 2Buffer: 98 0Retrived: bMode: ASCII, String: abcd, Buffer.Length: 4Buffer: 97 98 99 100Retrived: abcdMode: UTF8, String: abcd, Buffer.Length: 4Buffer: 97 98 99 100Retrived: abcdMode: Unicode, String: abcd, Buffer.Length: 8Buffer: 97 0 98 0 99 0 100 0Retrived: abcdMode: ASCII, String: 乙, Buffer.Length: 1Buffer: 63Retrived: ?Mode: UTF8, String: 乙, Buffer.Length: 3Buffer: 228 185 153Retrived: 乙Mode: Unicode, String: 乙, Buffer.Length: 2Buffer: 89 78Retrived: 乙Mode: ASCII, String: 甲乙丙丁, Buffer.Length: 4Buffer: 63 63 63 63Retrived: ????Mode: UTF8, String: 甲乙丙丁, Buffer.Length: 12Buffer: 231 148 178 228 185 153 228 184 153 228 184 129Retrived: 甲乙丙丁Mode: Unicode, String: 甲乙丙丁, Buffer.Length: 8Buffer: 50 117 89 78 25 78 1 78Retrived: 甲乙丙丁大体上可以得出这么几个结论:
•ASCII不能保存中文(貌似谁都知道=_-`)。
•UTF8是变长编码。在对ASCII字符编码时,UTF更省空间,只占1个字节,与ASCII编码方式和长度相同;Unicode在对ASCII字符编码时,占用2个字节,且第2个字节补零。
•UTF8在对中文编码时需要占用3个字节;Unicode对中文编码则只需要2个字节。

 

 

 

转载于:https://www.cnblogs.com/freeliver54/p/5633283.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/573367.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tomcat 设置java_为tomcat配置java环境变量

我的tomcat 中java标签里是这么写的java virual Machine:C:\Program Files\Java\jre1.6.0\bin\client\jvm.dlljava classpath:C:\Program Files\Apache Software Foundation\Tomcat 5.5\bin\bootstrap.jarjava options:-Dcatalina.homeC:\Program Files\Apache Software Founda…

项目开发流程标准

1 项目各阶段主要成果列表 项目阶段 主要内容 1、商务谈判阶段 《业务需求说明书》、《项目风险评估报告》、 《项目可行性报告书》&#xff08;可由市场或TC部提供&#xff09; 或1、技术部项目立项 《技术部项目立项表》、《项目可行性报告书》 2、计划与设计阶…

java servlet 3_java – Servlet 2.5和3之间有什么区别?

更新正如一个更新和更明确&#xff0c;这些是servlet 2.5和3之间的主要区别(我不想穷举&#xff0c;我只是提到最有趣的部分)&#xff1a;声明servlet&#xff0c;过滤器和监听器的注释(易于开发)在servlets 2.5中&#xff0c;要声明具有一个init参数的servlet&#xff0c;您需…

python 内置模块-re

想要在python中使用正则表达式&#xff0c;就需要先导入re模块&#xff0c;正则表达式是一个强大的功能&#xff0c;可以为我们节省很多工作量。 一、元字符&#xff1a; 用一些具有特殊含义的符号表示特定种类的字符或位置。. 匹配除换行符以外的任意字符\w匹配字母或数字或下…

java8 stringbuilder_为什么 Java 8 中不需要 StringBuilder 拼接字符串

在Java开发者中&#xff0c;字符串的拼接占用资源高往往是热议的话题.让我们深入讨论一下为什么会占用高资源。在Java中&#xff0c;字符串对象是不可变的&#xff0c;意思是它一旦创建&#xff0c;你就无法再改变它。所以在我们拼接字符串的时候&#xff0c;创建了一个新的字符…

js函数引用、函数调用与回调函数

var function1function2; 1.调用function1()函数的结果正好与调用function2()相同&#xff0c;因为两个函数都引用了相同的代码&#xff0c;因此函数名称也称为函数调用。 2.引用函数与调用函数的区别与函数名称后是否附有括号有关&#xff0c;函数引用只会单独出现&#xff0c…

c mysql dll_C:\Windows\libmysql_e.dll

这是C:\Windows\libmysql_e.dll下载&#xff0c;一款很重要的dll文件组件哦&#xff0c;如果你的电脑libmysql e.dll错误或者确实会导致很程序和软件都不能正常运行的哦&#xff0c;有需要的就来下载吧&#xff01;软件介绍C:\Windows\libmysql_e.dll是需要安装php和MySQL的工具…

FileInputStream 把文件作为字节流进行读操作

//把文件作为字节流进行读操作 FileInputStream in new FileInputStream(filename);//FileInputStream具体实现了在文件上读取数据转载于:https://www.cnblogs.com/xuedexin/p/5639327.html

java datetime 转换_如何实现Java日期时间格式转换

Java日期时间以及日期相互转换Java日期时间&#xff0c;以及相互转化&#xff0c;供大家参考&#xff0c;具体内容如下package com.study.string;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import …

Mac 使用常见问题汇集

1、Mac系统如何隐藏文件或文件夹&#xff1f; 在 Mac 文件的文件名前添加 . 即可使文件隐藏 2、Mac系统如何查看隐藏文件&#xff1f; 终端里面能用命令来控制: 显示Mac隐藏文件的命令&#xff1a;defaults write com.apple.finder AppleShowAllFiles YES 隐藏Mac隐藏文件的命令…

安卓手机的a/span的宽高失效

最近在做一个移动端的项目&#xff0c;网页版 在IOS上显示都是妥妥的&#xff0c;可是一部华为中的UC浏览器的效果就让人傻眼了&#xff0c;好多按钮都是都缩在一起&#xff0c;宽高失效。 折腾了半天找不到蛛丝马迹&#xff0c;最后实验发现<a><span>在华为手机中…

java model 封装_Java封装统一的Result Model案例

在开发过程中&#xff0c;有时候会需要使用错误码错误信息的形式&#xff0c;来返回某些业务操作的错误结果信息&#xff0c;来代替效率较低的异常传递。这样就需要封装一个统一的Result model作为返回值&#xff0c;代替直接返回数据等结果。1.定义错误码 - 错误信息接口错误码…

java 日期随机数_Java 生成指定时间范围的随机时间、随机中文姓名、随机字符姓名、随机数...

解决问题&#xff1a;Java生成指定时间范围的随机时间&#xff1f;Java生成随机中文姓名&#xff1f;Java生成随机字符姓名&#xff1f;Java生成随机数&#xff1f;代码&#xff1a;import java.io.UnsupportedEncodingException;import java.text.ParseException;import java.…

java语言程序设计基础篇14.6答案_《Java语言程序设计-基础篇》答案-第15章

第15章 异常和断言复习题15.1 答&#xff1a;略15.2 答&#xff1a;声明异常是为了在方法中产生异常时&#xff0c;以便通知方法的调用者。在方法声明的头部使用关键字throws 声明&#xff0c;一个方法可以声明多个异常。如&#xff1a;public void method() throws IOExceptio…

《机器学习》周志华 习题答案9.4

原题采用Kmeans方法对西瓜数据集进行聚类。我花了一些时间居然没找到西瓜数据集4.0在哪里&#xff0c;于是直接采用sklearn给的例子来分析一遍&#xff0c;更能说明Kmeans的效果。 #!/usr/bin/python # -*- coding:utf-8 -*- import numpy as np import matplotlib.pyplot as p…

一个电商项目的功能模块梳理

电商项目核心玩法&#xff1a;定制商品供应链&#xff08;商品辅料库&#xff09;网红社区最近做项目&#xff0c;功能越来越多&#xff0c;想清晰地理解项目&#xff0c;有点累了。今天抽空&#xff0c;把这个项目的核心功能模块简要总结下&#xff0c;顺便画了个图。一、全局…

java8 循环jsonarray_JSONArray 遍历方式

第一种(java8):遍历JSONArray 拼接字符串 public static void main(String[] args) {JSONArray jSONArray = new JSONArray(); JSONObject jb = new JSONObject(); jb.put("id", 1); jb.put("name", "s"); jSONArray.add(jb); JSONObject j1 = …

Codeforces Round #361(div 2)

A题题目意思很简单&#xff0c;问一种拨号的方式(拨号手势)是不是能拨出唯一的号码(例如253就不是唯一的&#xff0c;因为586也是可以的) 记录电话上每个格子上下左右是否还有格子&#xff0c;一个拨号手势是唯一的当且仅当&#xff0c;所拨号码的所有格子在同一个方向不同时有…

java货物进销管理系统_java实验 货物进销管理系统

实验二货物进销管理系统一&#xff0e;实验目的1&#xff0e;掌握Java中文件的读写操作。2&#xff0e;学会使用Java提供的实用类(Vector, ArrayList)来完成特定的功能。3&#xff0e;掌握字符串类(String, StringBuffer)的使用。4&#xff0e;掌握用面向对象的方法分析和解决复…

java forkjoin 简书_浅谈Java的Fork/Join并发框架

1. Fork/Join是什么Oracle的官方给出的定义是&#xff1a;Fork/Join框架是一个实现了ExecutorService接口的多线程处理器。它可以把一个大的任务划分为若干个小的任务并发执行&#xff0c;充分利用可用的资源&#xff0c;进而提高应用的执行效率。Fork/Join实现了ExecutorServi…