当前位置: 首页 > news >正文

网络编程_TCP通信综合练习:

1

image.png

//client::
public class Client {public static void main(String[] args) throws IOException {//多次发送数据//创建socket对象,填写服务器的ip以及端口Socket s=new Socket("127.0.0.1",10000);//获取输出流OutputStream op = s.getOutputStream();//因为要不断发送数据,所以可以使用Sacnner录入数据,结合循环将数据发出去Scanner sc=new Scanner(System.in);while (true) {//键盘录入System.out.println("请输入一个数据");String str = sc.next();//如果输入886就退出发送if ("886".equals(str)){break;}op.write(str.getBytes());}//关流s.close();}
}
//Server:
public class Server {public static void main(String[] args) throws IOException {//不断接收//创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);//等待客户端来连接Socket socket = ss.accept();//创建一个输入流对象InputStream is = socket.getInputStream();//转换流:字节转字符InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1) {System.out.print((char) b);}//关流socket.close();//关闭通道ss.close();//关闭服务器}
}

先启动服务器,再启动客户端
控制台:
image.pngimage.png

2

image.png

//client
public class Client {public static void main(String[] args) throws IOException {//客户端:发送一条数据,接收服务端反馈的消息并打印//服务器:接收数据并打印,再给客户端反馈消息//1.创建Socket对象并连接服务端Socket socket = new Socket("127.0.0.1",10000);//2.写出数据String str = "见到你很高兴!";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//写出一个结束标记,(结束输出流)socket.shutdownOutput();//3.接收服务端回写的数据InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1){System.out.print((char)b);}//释放资源socket.close();}
}//Server
public class Server {public static void main(String[] args) throws IOException {//客户端:发送一条数据,接收服务端反馈的消息并打印//服务器:接收数据并打印,再给客户端反馈消息//1.创建对象并绑定10000端口ServerSocket ss = new ServerSocket(10000);//2.等待客户端连接Socket socket = ss.accept();//3.socket中获取输入流读取数据InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);int b;//细节://read方法会从连接通道中读取数据//但是,需要有一个结束标记,此处的循环才会停止//否则,程序就会一直停在read方法这里,等待读取下面的数据while ((b = isr.read()) != -1){System.out.println((char)b);}//4.回写数据String str = "到底有多开心?";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//释放资源socket.close();ss.close();}
}

image.pngimage.png

3

image.png
下面的例子是传输图片,所以使用字节流

//Client
public class Client {public static void main(String[] args) throws IOException {//创建Socket对象连接服务器Socket s = new Socket("127.0.0.1", 10000);//读取图片文件:使用字节流//图片较大:使用缓冲流BufferedInputStream bis = new BufferedInputStream(new FileInputStream("..\\netcode\\clientdir\\a.jpg"));//在通道中获取字节流,输入数据到服务端BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());//边读边写byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//结束标识s.shutdownOutput();//接受服务端回馈:字节流-->字符流---->缓冲流BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));int b;while((b=br.read())!=-1){System.out.print((char) b);}//关流s.close();}
}//server
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);//等待客户端连接Socket socket = ss.accept();//获取通道中传来的数据//字节流读取字节//缓冲流提升效率BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//输出到本地BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("..\\netcode\\serverdir\\a.jpg"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//返回信息:字节流-->字符流---->缓冲流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();//关流socket.close();ss.close();}}

image.pngimage.png

4.

image.png

//client
public class Client {public static void main(String[] args) throws IOException {//创建Socket对象连接服务器Socket s = new Socket("127.0.0.1", 10000);//读取图片文件:使用字节流//图片较大:使用缓冲流BufferedInputStream bis = new BufferedInputStream(new FileInputStream("..\\netcode\\clientdir\\a.jpg"));//在通道中获取字节流,输入数据到服务端BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());//边读边写byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//结束标识s.shutdownOutput();//接受服务端回馈:字节流-->字符流---->缓冲流BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));int b;while((b=br.read())!=-1){System.out.print((char) b);}//关流s.close();}
}//Server
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);//等待客户端连接Socket socket = ss.accept();//获取通道中传来的数据//字节流读取字节//缓冲流提升效率BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//随机uuid、String str = UUID.randomUUID().toString().replace("-", "");//输出到本地BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("..\\netcode\\serverdir\\" + str + ".jpg"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//返回信息:字节流-->字符流---->缓冲流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();//关流socket.close();ss.close();}}

image.png

5.

image.png
服务端不停止,用户端一直传
思路:可以在服务端使用循环嵌套:
如下:

public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);while (true) {//等待客户端连接Socket socket = ss.accept();//获取通道中传来的数据//字节流读取字节//缓冲流提升效率BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//随机uuid、String str = UUID.randomUUID().toString().replace("-", "");//输出到本地BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("..\\netcode\\serverdir\\" + str + ".jpg"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);//当第一个用户还在传输时,服务端代码还会在这不断循环}bos.flush();//返回信息:字节流-->字符流---->缓冲流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();//关流socket.close();//断开当前通道//ss.close();//关闭服务器    ----这里不可以让服务器关闭}}
}

但是循环有弊端,它是一种单线程,如果说此时要传输的文件很大,当第一个用户还在传输时,服务端代码还会停止在第25行,此时就无法和第二个用户产生连接(只有完成一次循环后,才能和下一个用户进行数据连接),所以我们可以用多线程来改进。使多个用户可以同时传输数据,服务端也可以同时读取多个用户的数据

//多线程
public class MyThread  extends Thread{Socket socket;public MyThread (Socket socket){this.socket=socket;}@Overridepublic void run() {//获取通道中传来的数据//字节流读取字节//缓冲流提升效率try {BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//随机uuid、String str = UUID.randomUUID().toString().replace("-", "");//输出到本地BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("..\\netcode\\serverdir\\" + str + ".jpg"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//返回信息:字节流-->字符流---->缓冲流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();} catch (IOException e) {throw new RuntimeException(e);}finally {//5.释放资源if (socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}//Server
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);while (true) {//等待客户端连接Socket socket = ss.accept();new MyThread(socket).start();//ss.close();}}
}//client....

6.

image.png
使用自定义线程池

//Server
public class Server {public static void main(String[] args) throws IOException {//1创建线程池对象ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心线程数量16,//线程池总大小60,//空闲时间TimeUnit.SECONDS,//单位new ArrayBlockingQueue<>(2),//队列Executors.defaultThreadFactory(),//线程工厂,让线程池如何创建线程对象new ThreadPoolExecutor.AbortPolicy()//拒绝策略);//2创建ServerSocket对象ServerSocket ss = new ServerSocket(10000);while (true) {//3等待客户端连接Socket socket = ss.accept();//开启一条线程//一个用户就对应服务端的一条线程//调用submit方法传入myRunnable对象pool.submit((new MyRunnable(socket)));//ss.close();}}
}
//MyRunnable
public class MyRunnable implements Runnable {Socket socket;public MyRunnable(Socket socket){this.socket=socket;}@Overridepublic void run() {//获取通道中传来的数据//字节流读取字节//缓冲流提升效率try {BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//随机uuid、String str = UUID.randomUUID().toString().replace("-", "");//输出到本地BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("..\\netcode\\serverdir\\" + str + ".jpg"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.flush();//返回信息:字节流-->字符流---->缓冲流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();} catch (IOException e) {throw new RuntimeException(e);}finally {//5.释放资源if (socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
//client.....

7.

image.png

public class Server {public static void main(String[] args) throws IOException {//客户端:多次发送数据//服务器:接收多次接收数据,并打印//1.创建对象绑定10000端口ServerSocket ss = new ServerSocket(10000);//2.等待客户端来连接Socket socket = ss.accept();//3.读取数据InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) != -1){System.out.print((char)b);}//4.释放资源socket.close();ss.close();}
}

首先启动服务端:
再在浏览器输入:
image.png
获得到数据:
image.png

8.

image.png
client

package A;import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class Client1 {public static void main(String[] args) throws IOException {/*** 每一个客户端都是一个线程*/while (true) {//1.与服务端建立连接Socket socket = new Socket("127.0.0.1", 10000);System.out.println("服务器已连接");//2生成聊天界面System.out.println("==============欢迎来到黑马聊天室================");System.out.println("1登录");System.out.println("2注册");System.out.println("请输入您的选择:");//3键盘录入Scanner sc = new Scanner(System.in);String choose = sc.nextLine();//判断:switch (choose) {case "1"://登录逻辑login(socket);break;case "2"://注册逻辑break;default:System.out.println("没有该选项");}}}/*** //登录** @param socket* @throws IOException*/private static void login(Socket socket) throws IOException {//1输入账户和密码Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();//***登录要求使用username=zhangsan&password=123这种格式发给服务端//2拼接StringBuilder sb = new StringBuilder();sb.append("username=").append(username).append("&password=").append(password);//3提交给服务器验证BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//第一次是告诉服务器是此时登陆操作是什么bw.write("login");bw.newLine();//这两个要配套使用bw.flush();//第二次告诉服务器用户端输入的账号密码bw.write(sb.toString());bw.newLine();bw.flush();//接收服务端的回馈消息BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String message = br.readLine();if ("1".equals(message)) {System.out.println("登陆成功,可以开始聊天");//开一条单独的线程,专门用来接收服务端转发过来的聊天记录new Thread(new ClientMyRunnable(socket)).start();//将要说的话传给服务器,交给服务器转发给其他客户端talk2All(bw);} else if ("2".equals(message)) {System.out.println("密码不正确");} else {System.out.println("用户名不存在,请先注册");}}private static void talk2All(BufferedWriter bw) throws IOException {Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入你要说的话");String message = sc.nextLine();bw.write(message);bw.newLine();bw.flush();}}
}class ClientMyRunnable implements Runnable {Socket socket;//构造public ClientMyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {//循环包裹,不断读取服务端发过来的信息(接受群发消息)while (true) {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String message = br.readLine();System.out.println(message);} catch (IOException e) {throw new RuntimeException(e);}}}
}

server

package A;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.Buffer;
import java.nio.file.attribute.UserPrincipal;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class Server {//成员位置方便调用static  ArrayList<Socket>list=new ArrayList<>();public static void main(String[] args) throws IOException {//1创建ServerSocket对象,并连接10000端口ServerSocket ss = new ServerSocket(10000);//2把本地文件中的正确用户名和密码都获取到Properties prop = new Properties();FileInputStream fis = new FileInputStream("..\\Chat\\account.txt");prop.load(fis);fis.close();//只要来了一个客户端,就开一个条线程while (true) {//等待服务端连接Socket socket = ss.accept();System.out.println("有客户端来连接");//开始处理线程任务new Thread(new MyRunnable(socket, prop)).start();}}
}//-----------------------------------------------------------------------
class MyRunnable implements Runnable {Socket socket;Properties prop;//构造public MyRunnable(Socket socket, Properties prop) {this.socket = socket;this.prop = prop;}@Overridepublic void run() {/*** 每一个线程要做的事情*/try {//1读取客户端传来的信息BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//第一次读取的是用户的操作String choose = br.readLine();while (true) {switch (choose) {case "login" -> login(br);case "register" -> register();}}} catch (IOException e) {throw new RuntimeException(e);}}/*** 1.获取用户端输入的帐号、密码* 2.与正确的账号密码比较* 3.写出不同情况的返回信息*/public void login(BufferedReader br) throws IOException {System.out.println("用户执行了登陆操作");//第二次读取的是用户端传递过来的拼接信息:username=zhangsan&password=123String userInfo = br.readLine();//获取真正的账号密码:切割String s1 = userInfo.split("&")[0];String s2 = userInfo.split("&")[1];String usernameInput = s1.split("=")[1];String passwordInput = s2.split("=")[1];System.out.println("账号是:" + usernameInput);System.out.println("密码是:" + passwordInput);//比较if (prop.containsKey(usernameInput)) {//用户名一致,就比较密码//先获取当前正确密码String rellyPassword = (String) prop.get(usernameInput);if (passwordInput.equals(rellyPassword)) {//登陆成功,给用户端返回信息messageToClient("1");//登陆成功,可以开始聊天//登陆成功后需要将当前socket对象存储起来Server.list.add(socket);//接收客户端发送的信息并打印在控制台talk2All(br,usernameInput);} else {//密码不正确,给用户端返回信息messageToClient("2");//密码不正确}} else {//用户名不存在,给用户端返回信息:messageToClient("3");//用户名不存在,请先注册}}private void talk2All(BufferedReader br, String usernameInput) throws IOException {//聊天死循环while(true){//接收客户端发送的信息String message = br.readLine();System.out.println(usernameInput+"发送过来了消息:"+message);//群发for (Socket s : Server.list) {//s以此表示每一个socket对象messageToClient(s,usernameInput+"发送过来了消息:"+message);}}}/***因为三种情况:登陆成功、密码不正确、用户名不存在都要返回信息给客户端,所以干脆抽取成方法* @param message*/public void messageToClient(String message) throws IOException {//获取输出流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}/*** 重载的messageToClient* @param socket* @param message*/public void messageToClient(Socket socket,String message) throws IOException {//获取输出流,将数据写给当前的socket通道对象BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}/*** 注册逻辑*/private static void register() {System.out.println("用户执行了注册操作");}}

相关文章:

  • Midjourney绘图欣赏系列(一)
  • Python爬虫html网址实战笔记
  • 单测的思路
  • 【Git】Java 使用 JGit 创建 Git 代码仓库
  • 【电路笔记】-LR串联电路
  • 天锐绿盾 | 办公终端文件数据\资料防泄密软件
  • 使用消息中间件实现系统间的异步通信和解耦
  • HttpClient:HTTP GET请求的服务器响应输出
  • 「算法」滑动窗口
  • 入门者拿捏 Java 的必备小秘诀
  • Linux:docker在线仓库(docker hub 阿里云)基础操作
  • VMwareWorkstation17.0虚拟机安装搭建Windows 11虚拟机(完整图文详细步骤教程)
  • Python学习路线图
  • ⭐北邮复试刷题103. 二叉树的锯齿形层序遍历 (力扣每日一题)
  • 模拟发送 Ctrl+Alt+Del 快捷键
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【翻译】babel对TC39装饰器草案的实现
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • es6要点
  • GitUp, 你不可错过的秀外慧中的git工具
  • HashMap ConcurrentHashMap
  • java正则表式的使用
  • pdf文件如何在线转换为jpg图片
  • springMvc学习笔记(2)
  • Terraform入门 - 1. 安装Terraform
  • yii2中session跨域名的问题
  • 从0到1:PostCSS 插件开发最佳实践
  • 从0实现一个tiny react(三)生命周期
  • 搭建gitbook 和 访问权限认证
  • 前端存储 - localStorage
  • 入手阿里云新服务器的部署NODE
  •  一套莫尔斯电报听写、翻译系统
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​如何在iOS手机上查看应用日志
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • ​香农与信息论三大定律
  • # Maven错误Error executing Maven
  • #pragma multi_compile #pragma shader_feature
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (c语言)strcpy函数用法
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (转)树状数组
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • *Django中的Ajax 纯js的书写样式1
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET CLR Hosting 简介
  • .NET delegate 委托 、 Event 事件
  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET处理HTTP请求
  • .net反编译的九款神器