Java网络编程基础

勿忘初心做自己  金牌会员 | 2023-10-20 19:23:44 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 977|帖子 977|积分 2931

Java网络编程基于TCP/UDP协议的基础之上,TCP/IP协议是一个协议簇。里面包括很多协议的,UDP只是其中的一个, 之所以命名为TCP/IP协议,因为TCP、IP协议是两个很重要的协议,就用他两命名了。那么首先我们先介绍一下TCP和UDP的特点:
1.TCP(Transmission Control Protocol,传输控制协议)是面向连接的,也就是说在以TCP协议发送数据的之前需要两台主机建立连接,一个TCP连接必须要经过三次“对话”才能建立起来,也俗称“三次握手”,其中的过程非常复杂,下面将以简单的形式介绍一下三次握手的过程:
有两台主机,主机A与主机B。
1)主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;
2)主机B向主机A发送同意连接和要求同步 (同步就是两台主机一个在发送,一个在接收,协调工作)的数据包 :“可以,你什么时候发?”,这是第二次对话;
3)主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”, 这是第三次对话。
三次“对话”的目的是使数据包的发送和接收同步, 经过三次“对话”之后,主机A才向主机B正式发送数据。
TCP建立连接需要三次握手,而断开连接需要四次,即四次挥手:
1)主机A向主机B发送请求断开连接,这是第一次对话;
2)主机B收到主机A的断开连接请求,返回确认,这是第二次对话;
3)主机B在接收完所有数据之后,向主机A发送确认断开连接,这是第三次对话;
4)主机A回复确认断开,这是第四次对话;
这四次对话完成之后,主机A和主机B才正式断开连接。
2.UDP(User Data Protocol,用户数据报协议),与TCP相反,UDP是不面向连接的协议,所以也是不可靠传输,只能尽力传输数据而保证数据传输的可靠性,常用于视频会议或者消息发送等服务。
了解了基本的概念特点之后,我们将使用Java编程的方式来实现基于这两种协议的数据传输过程:
UDP

传输数据与我们生活中寄快递很相似,在寄快递的时候,我们首先要用一个盒子将物品打包起来,再通过物流公司寄送出去,那么传输数据也是类似的:
首先client,DatagramSocket对象就类似与快递公司,负责最后的物品寄送,DatagramPacket对象就类似于打包过程,将所需要的数据进行打包。
  1. 1 public class SendMessageDemo {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3         //采用UDP协议发送数据
  4. 4         //1.创建DatagramSocket对象(快递公司,负责发送数据)
  5. 5         //空参 随机绑定一个端口号进行使用 有参则指定端口号进行绑定
  6. 6         DatagramSocket ds = new DatagramSocket();
  7. 7         InetAddress address = InetAddress.getByName("127.0.0.1");
  8. 8         int port = 10087;
  9. 9         //2.打包数据,用字节数组的形式发送
  10. 10         String str = "Hello world!";
  11. 11         byte[] bytes = str.getBytes();
  12. 12         DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
  13. 13         //3.发送数据
  14. 14         ds.send(dp);
  15. 15         //4.释放资源
  16. 16         ds.close();
  17. 17
  18. 18     }
  19. 19 }
复制代码
对于Server端,接收到client发送的数据之后,需要对这些字节进行解析,才能够知道发送的是什么内容:
  1. 1 public class ReceiveMessageDemo {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3         //先运行接收进程,再运行发送进程
  4. 4         //创建快递公司用来接收数据包,必须绑定跟发送端发送的端口一致
  5. 5         DatagramSocket ds = new DatagramSocket(10087);
  6. 6
  7. 7         //2.接收数据包
  8. 8         byte[] bytes = new byte[1024];
  9. 9         //使用空的数据包存储数据
  10. 10         DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
  11. 11         //该方法是阻塞的,会一直等待发送方发送消息
  12. 12         ds.receive(dp);
  13. 13
  14. 14         //3.解析数据包
  15. 15         byte[] data = dp.getData();//获取接收到的数据
  16. 16         int length = dp.getLength();//获取接收到的数据的长度
  17. 17         String str = new String(data,0,length);//解析成字符串的形式
  18. 18         InetAddress address = dp.getAddress();//获取发送方的IP信息
  19. 19         int port = dp.getPort();
  20. 20         System.out.println("接收到的信息为:"+str+",来自主机:"+address+"端口为:"+port);
  21. 21         System.out.println("长度为:"+length);
  22. 22
  23. 23
  24. 24     }
  25. 25 }
复制代码
如果想发送多条消息呢?我们可以使用while循环来接收用户键盘输入的消息:
  1. 1 public class SendMessageAgent {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3
  4. 4         //发送方端口可以不指定随机使用
  5. 5         DatagramSocket ds = new DatagramSocket();
  6. 6
  7. 7         //创建要发送的数据包
  8. 8         Scanner scanner = new Scanner(System.in);
  9. 9         while(true) {
  10. 10             System.out.println("请输入你要发送的内容:");
  11. 11             String s = scanner.nextLine();
  12. 12             if (s.equals("886")) {
  13. 13                 break;
  14. 14             }
  15. 15             //将输入的字符串转为字节数组发送
  16. 16             byte[] message = s.getBytes();
  17. 17
  18. 18             //选择发送的主机和端口
  19. 19             InetAddress address = InetAddress.getByName("127.0.0.1");
  20. 20             int port = 10088;
  21. 21             DatagramPacket dp = new DatagramPacket(message, message.length, address, port);
  22. 22
  23. 23             //发送
  24. 24             ds.send(dp);
  25. 25         }
  26. 26         //释放资源
  27. 27         ds.close();
  28. 28     }
  29. 29 }
复制代码
TCP

如果要使用TCP协议发送数据,那么和UDP所需要的对象是不一样的:
  1. 1 public class Client {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3         //TCP协议
  4. 4         //1.创建socket对象
  5. 5         //该对象绑定需要连接的主机与端口,如果连接失败则代码报错
  6. 6         Socket socket = new Socket("127.0.0.1",10000);
  7. 7
  8. 8         //TCP中以IO输出流的形式发送,以输入流的形式接收
  9. 9         //2.获取输出流,并写入数据
  10. 10         OutputStream os = socket.getOutputStream();
  11. 11         os.write("hello world!你们好".getBytes());
  12. 12
  13. 13         //释放资源 这里进行四次挥手
  14. 14         os.close();
  15. 15         socket.close();
  16. 16
  17. 17     }
  18. 18 }
复制代码
  1. public class Server {
  2.     public static void main(String[] args) throws IOException {
  3.         //1.创建serverSocket,并绑定接收端口(必须与发送的端口相同)
  4.         ServerSocket socket = new ServerSocket(10000);
  5.         //2.监听连接,如果连接成功则返回一个socekt对象,没有连接成功则阻塞等待
  6.         Socket accept = socket.accept();//这里进行三次握手
  7.         //3.从accept中读取输入流,并获取信息
  8.         InputStream is = accept.getInputStream();
  9.         //字节流,一个字节一个字节的读入,但是中文会出错,一个中文三个字节,读入的时候会导致中文乱码
  10.         InputStreamReader isr = new InputStreamReader(is);//字符流,一个字符一个字符的读入,解决中文问题
  11.         BufferedReader br = new BufferedReader(isr);//提升读取效率
  12.         int b;
  13.         while((b=br.read()) != -1){//需要定义结束标记,不然会一直卡死在这里等待读取
  14.             System.out.print((char) b);
  15.         }
  16.         //收到信息后写入反馈
  17.         InetAddress address = accept.getInetAddress();
  18.         OutputStream outputStream = accept.getOutputStream();
  19.         String returnMessage = "已经收到:"+address.getHostAddress()+address.getHostName()+"发来的信息!";
  20.         outputStream.write(returnMessage.getBytes());
  21.         //4.释放资源
  22.         accept.close();
  23.         socket.close();
  24.     }
  25. }
复制代码
需要先运行server端代码,再运行client端代码,因为client端如果没有找到对应主机则会报错。
 文件传输

client端:
  1. 1 public class client {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3         Socket socket = new Socket("127.0.0.1",10000);
  4. 4
  5. 5         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet/clientdir/neural.png"));
  6. 6         BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
  7. 7
  8. 8         byte[] bytes = new byte[1024];
  9. 9         int len;
  10. 10         while((len=bis.read(bytes)) != -1){
  11. 11             bos.write(bytes,0,len);
  12. 12         }
  13. 13
  14. 14         socket.shutdownOutput();
  15. 15         //获取服务器的回写数据
  16. 16         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  17. 17         String line = br.readLine();
  18. 18         System.out.println(line);
  19. 19
  20. 20         socket.close();
  21. 21     }
  22. 22 }
复制代码
通过多线程来解决多用户同时上传文件的问题,每有一个用户建立连接就新创建一个线程来处理上传文件的请求,可以采用线程池进行优化,采用runnable的方式创建线程,这样我们可以定义自己的runnable方法来处理文件上传请求:
  1. 1 public class server {
  2. 2     public static void main(String[] args) throws IOException {
  3. 3
  4. 4         ServerSocket serverSocket = new ServerSocket(10000);
  5. 5         Socket accept = serverSocket.accept();
  6. 6         //每建立一个连接,就创建一个线程来处理上传请求!
  7. 7         //创建线程池对象
  8. 8         ThreadPoolExecutor pool = new ThreadPoolExecutor(
  9. 9                 3,//核心线程数量
  10. 10                 16,//线程池总大小
  11. 11                 60,//空闲时间
  12. 12                 TimeUnit.SECONDS,
  13. 13                 new ArrayBlockingQueue<Runnable>(2),
  14. 14                 Executors.defaultThreadFactory(),
  15. 15                 new ThreadPoolExecutor.AbortPolicy()
  16. 16         );
  17. 17         //new Thread(new SocketRunnable(accept) ).start();
  18. 18         pool.submit(new SocketRunnable(accept));
  19. 19
  20. 20     }
  21. 21 }
复制代码
  1. public class SocketRunnable implements Runnable{
  2.     Socket accept;
  3.     public SocketRunnable(Socket accept){
  4.         this.accept = accept;
  5.     }
  6.     @Override
  7.     public void run() {
  8.         try {
  9.             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet/serverdir/neural.png"));
  10.             BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
  11.             byte[] bytes = new byte[1024];
  12.             int len;
  13.             while ((len = bis.read(bytes)) != -1) {
  14.                 bos.write(bytes, 0, len);
  15.             }
  16.             //回写数据
  17.             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
  18.             bw.write("上传成功!");
  19.             bw.newLine();
  20.             bw.flush();
  21.         }catch (Exception e){
  22.             System.out.println("上传失败");
  23.         }finally {
  24.             try {
  25.                 if(accept != null){
  26.                 accept.close();}
  27.             } catch (IOException e) {
  28.                 throw new RuntimeException(e);
  29.             }
  30.         }
  31.     }
  32. }
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

勿忘初心做自己

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表