欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > 网络编程练习

网络编程练习

2024/10/24 23:24:44 来源:https://blog.csdn.net/m0_46977298/article/details/141891567  浏览:    关键词:网络编程练习

一、UDP

聊天室

UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束。

UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收。

(1)一个人发送多次数据

发送端代码:

public class sendMessage {public static void main(String[] args) throws IOException {//1.找到快递公司DatagramSocket ds = new DatagramSocket();//2.封装数据//键盘录入数据Scanner sc = new Scanner(System.in);while (true) {String s = sc.next();if (s.equals("886")) {break;}byte[] bytes = s.getBytes();InetAddress ip = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, ip, port);//3.发送数据ds.send(dp);}//4.释放资源ds.close();}
}

接收端代码:

public class receiveMessage {public static void main(String[] args) throws IOException {//一定要绑定端口号//表示从哪个端口接收数据DatagramSocket ds = new DatagramSocket(10086);//创建一个包用来接收数据byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);while (true) {//进行接收ds.receive(dp);//解析数据byte[] data = dp.getData();String str = new String(data);InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到的数据为:" + str);System.out.println("由ip为" + address + ",端口号为" + port + "进行发送");}}
}

多个发送端发送数据: Edit Configurations --> Modify options -->Allow multiple instance,就可以一次运行多个发送端程序。

二、TCP

1、多发多收

客户端:多次发送数据
服务器:接收多次接收数据,并打印

(1)客户端代码:

public class Client {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 10086);OutputStream is = socket.getOutputStream();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入信息:");String s = sc.next();is.write(s.getBytes());if (s.equals("886")) {break;}}socket.close();}
}

(2)服务器端代码:

public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String str;while ((str = br.readLine()) != null) {System.out.println(str);}socket.close();ss.close();}
}

①关于服务端这段代码,使用缓冲字符流读取,客户端循环输入数据,但是只有在客户端发送886结束循环之后服务端才能接收到数据。

运行结果:

不建议使用缓冲流的readLine方法,如果使用需要特意在后面加换行符才可以否则也会阻塞?不知道。 

②但是如果使用字符流读取的话,就是一次输入结束之后就会进行读取。

2 、接收和反馈

客户端发送一条数据,服务器接收数据并打印,再给客户端回复消息,客户端接收服务端回复的消息并打印。

Tips:当客户端数据输入结束但并没有关闭连接时,其实服务端还一直在等待客户端的数据,就是阻塞在读取数据上;但是客户端关闭数据连接的通道也作为一种结束标记,所以服务端知道客户端数据发完了,就不会阻塞在读取数据上了。

总结:

在数据传输时,服务端会阻塞在读取数据上,只有看到结束标记时跳出(就是你客户端发完了,你要让我服务端知道你发完了啊)。客户端关闭数据连接的通道和socket.shutdownOutput()都作为一种结束标记。

服务端代码:

(1)当向客户端回复时,通过通道对象socket获取输出流。

public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) !=-1) {System.out.print((char)b);}OutputStream os = socket.getOutputStream();String s = "me too";os.write(s.getBytes());socket.close();ss.close();}
}

客户端代码: 

(1)当客户端数据发送结束之后,但是又不能关闭连接时,可以有一个结束标志来告诉服务端我的数据已经发送完毕了,通过socket.shutdownOutput();。

(2)当客户端接收来自服务端的回复时,通过通道对象socket获取输入流。

public class Client {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 10086);OutputStream is = socket.getOutputStream();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入信息:");String s = sc.next();is.write(s.getBytes());if (s.equals("886")) {break;}}//关闭输入流,表示数据已经传输完毕socket.shutdownOutput();InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) !=-1) {System.out.print((char)b);}socket.close();}
}
3、上传文件

客户端:将本地文件上传到服务器。接收服务器的反馈。
服务器:接收客户端上传的文件,上传完毕之后给出反馈。

(1)客户端代码:

public class Client {public static void main(String[] args) throws IOException {//客户端连接Socket socket = new Socket("127.0.0.1", 10086);//输出数据OutputStream os = socket.getOutputStream();//读取文件FileInputStream fis = new FileInputStream("name_10.txt");int b1;while ((b1 = fis.read()) != -1) {os.write(b1);}fis.close();//给出数据输入结束标记socket.shutdownOutput();//接收服务端的回复InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b2;while ((b2 = isr.read()) !=-1) {System.out.print((char)b2);}//关闭连接socket.close();}
}

(2)服务端代码:

public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();InputStream is = socket.getInputStream();FileOutputStream fos = new FileOutputStream("name_copy.txt");int b;while ((b = is.read()) != -1) {fos.write(b);}OutputStream os = socket.getOutputStream();os.write("收到".getBytes());socket.close();ss.close();}
}
4、文件名重复

在3的代码中,上传到服务器的文件名字都是相同的,这样很不方便啊。

在Java中有一个UUID类,提供了一个静态方法randomUUID(),输出是以下这种格式的数据。大概明白了为什么下载文件时名字总是一些类似的数字什么的。

对3的代码进行修改:

5 、上传文件(多线程版)

想要服务器不停止,能接收很多用户上传的图片,
该怎么做呢?
提示:可以用循环或当多线程。但是循环不合理,最优解法是(循环+多线程)改写。

首先是循环的写法:

但是这种情况下很容易造成一个用户的文件没上传完毕,下一个用户就来了,容易错过第二个用户的上传需求,有问题。

那么如何解决呢?可以使用线程。

每一个用户的需求都使用一个单独的线程进行解决。

线程的代码如下:

public class MyThread extends Thread{private Socket socket;public MyThread(Socket socket){this.socket = socket;}@Overridepublic void run() {try {InputStream is = socket.getInputStream();String name = UUID.randomUUID().toString().replace("-", "");FileOutputStream fos = new FileOutputStream(name + ".txt");int b;while ((b = is.read()) != -1) {fos.write(b);}OutputStream os = socket.getOutputStream();os.write("收到".getBytes());} catch (IOException e) {throw new RuntimeException(e);} finally {if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}

服务端的代码如下:

当服务器监测到有用户建立连接时,用创建一个线程去处理它的需求。

public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);while (true) {Socket socket = ss.accept();new MyThread(socket).start();}//ss.close();}
}
6、上传文件(线程池版)

代码如下:

7、BS(接收浏览器的消息并打印)

客户端:不需要写
服务器:接收数据并打印。 

在浏览器的网址中输入127.0.0.1:10086

输出结果如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com