黑马程序员——第十一章 网络编程

 

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


 

1.  InetAddress

表示互联网协议 (IP) 地址

代码示例

public class NetDemo {

   public static void main(String[] args) throws Exception {

      //获取本地IP实例

      InetAddress address=InetAddress.getLocalHost();

      //输出本地IP地址以及主机名

      System.out.println(address.getHostAddress()+":"+address.getHostName());

     

      //获取指定主机的地址对象

      InetAddress address2=InetAddress.getByName("192.168.1.18");

      //打印指定主机的IP地址以及主机名

      System.out.println(address2.getHostAddress()+":"+address2.getHostName());

     

      InetAddress ip=InetAddress.getByName("www.baidu.com");

      System.out.println(ip.getHostAddress()+":"+ip.getHostName());

 

   }

}

2.UDP数据报文包协议

无连接,不可靠的协议

不需要建立连接,所以效率高

每个数据报大小限制在64K内

 

DatagramSocket:表示用来发送和接收数据报包的套接字

DatagramPacket:此类表示数据包

 

数据包分为发送数据包和接收数据包

凡是发送数据包,参数都是带着地址的

 

UDP是无连接不可靠的协议,所以在没有接收端的情况下,发送端可以发送数据,且不会抛错,只不过是数据发丢了

代码示例

(1)   发送数据到接收端并显示

/*

 * 通过UDP协议发送一段文本数据

 *

 * 接收端

 *    思路:

 *     1.先建立UDPSocket.它具备发送或者接收功能

 *     2.将数据封装到数据包中。数据包对象:DatagramPacket

 *     3.使用Socket对象的send方法将数据包发送出去

 *     4.关闭资源

 */

public class UDPSender {

   public static void main(String[] args) throws IOException {

      System.out.println("UDP发送端运行");

 

      // 1.建立Socket

      DatagramSocket ds = new DatagramSocket();

 

      // 2.将数据封装到数据包中

      String text = "UDP,你好";

      // 将数据转成字节数组

      byte[] buff = text.getBytes();

      // 将字节数组封装到数据包中

      InetAddress address = InetAddress.getByName("ZFY");

      DatagramPacket dp = new DatagramPacket(buff,buff.length,address,

            10086);

 

      // 3.使用Socket对象的send方法发出数据包

      ds.send(dp);

 

      // 4.关闭资源

      ds.close();

 

      System.out.println("发送结束");

   }

}

  

/*

 * UDP接收端,接收发送过来的数据,并显示在屏幕上

 * 思路:

 *     1.先有UDP Socket服务(接收端必须明确端口,否则无法接收数据)

 *     2.接收数据

 *     3.先定义数据包

 *     4.通过数据包对象获取数据包内容:发送端IP、端口、数据

 *     5.关闭资源

 */

public class UDPReceive {

   public static void main(String[] args) throws Exception {

      System.out.println("UDP接收端运行");

     

      //1 创建Socket服务

      DatagramSocket ds=new DatagramSocket(10086);

     

      //2 3 接收数据,将数据存储到数据包

      byte[] buff=new byte[1024];

      DatagramPacket dp=new DatagramPacket(buff,buff.length);

      ds.receive(dp);//阻塞

     

      //4 获取数据包内容

      String ipString=dp.getAddress().getHostAddress();

      int port=dp.getPort();

      String text=new String(dp.getData(),0,dp.getLength());

     

      System.out.println("接收到来自"+ipString+":"+port+"的数据:"+text);

     

      //5  关闭资源

      ds.close();

      System.out.println("UDP接收结束");

   }

}

(2)键盘录入信息发到接收端,由接收端将数据发回到发送端进行显示

 

/*

 * 发送端:从键盘录入数据发送到接收端,输入bye退出

 *

 */

public class UDPSender {

   public static void main(String[] args) throws Exception {

      System.out.println("发送端启动");

      System.out.println("等待输入信息...");

      //创建Socket

      DatagramSocket socket=new DatagramSocket(10001);

      DatagramPacket dp=null;

      //获取本机地址

      InetAddress address=InetAddress.getByName("127.0.0.1");

     

      //从键盘录入信息

      BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

      String line=null;

      byte[] buff=null;

      while((line=br.readLine())!=null){

         buff=line.getBytes();

         //创建数据包

         dp=new DatagramPacket(buff,buff.length,address,10010);

         //发送数据

         socket.send(dp);

         if(("bye".equals(line))){

            break;

         }

         //接收从服务端发来的信息

         socket.receive(dp);

         //打印来自服务端的信息

         System.out.println("来自接收端的信息:"+new String(dp.getData(),0,dp.getLength()));

        

      }

      //关闭资源

      br.close();

      socket.close();

      System.out.println("发送端关闭");

   }

}

 

 

/*

 * 接收端:接收信息并显示到控制台,返回数据给发送端,接收到bye退出

 */

public class UDPReceive {

   public static void main(String[] args) throws Exception {

      System.out.println("接收端启动");

     

      //创建Socket

      DatagramSocket socket=new DatagramSocket(10010);

      byte[] buff=new byte[1024];

      //创建接收数据包

      DatagramPacket recdp=new DatagramPacket(buff,buff.length);

      //创建发送数据包

      DatagramPacket senddp=null;

     

      //接收来自客户端的数据包

      socket.receive(recdp);

      String line=null;

 

      while((line=new String(recdp.getData(),0,recdp.getLength())) != null&&!("bye".equals(line))){

         //打印来自客户端的信息

         System.out.println("来自发送端的信息:"+line);

         byte[]sendbuff=line.getBytes();

         //发送数据包到客户端

         senddp=new DatagramPacket(sendbuff,sendbuff.length,recdp.getAddress(),recdp.getPort());

         socket.send(senddp);

        

         //等待接收来自客户端的数据

         socket.receive(recdp);

      }

      //关闭资源

      socket.close();

      System.out.println("接收端关闭");

 

   }

}

 

(3)通过UDP实现群聊

 

/*

 * 案例:通过UDP实现群聊

 *     思路:

 *        1.这个程序中既有收,又有发,需要同时执行,需要用到多线程技术

 *          一个线程负责发送,一个线程负责接收

 */

public class UDPChatTest {

   public static void main(String[] args) throws Exception {

      //定义发送端socket

      DatagramSocket sendDs=new DatagramSocket();

     

      //定义接收端socket

      DatagramSocket recDs=new DatagramSocket(10086);

     

      //发送&接收

      Send send=new Send(sendDs);

      Receive rec=new Receive(recDs);

     

      Thread t1=new Thread(send);

      Thread t2=new Thread(rec);

     

      //启动线程

      t1.start();

      t2.start();

   }

 

}

 

 

/*

 * 发送端代码

 */

public class Send implements Runnable {

 

   private DatagramSocketds;

   private DatagramPacketdp;

  

   public Send(DatagramSocketds) {

      this.ds =ds;

   }

 

   @Override

   public void run() {

      try{

         //从键盘录入信息

         BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

         String line=null;

         while((line=br.readLine())!=null){

            byte[]by=line.getBytes();

            //实现局域网群聊,每个网段的最后一位如果写成255,没有此台主机,他会发往该网段的所有主机X.X.X.255

            //dp=newDatagramPacket(by,by.length,InetAddress.getByName("192.168.1.255"),10086);

           

            //发送信息到指定接收端

            dp=new DatagramPacket(by,by.length,InetAddress.getByName("127.0.0.1"),10086);

            ds.send(dp);

           

            //输入over,则推出聊天

            if("over".equals(line)){

                System.out.println("关闭发送端");

                break;

            }

         }

         ds.close();

      }

      catch(Exceptione){

         e.printStackTrace();

      }

 

   }

}

 

 

/*

 * 接收端代码

 */

public class Receive implements Runnable {

   private DatagramSocketds;

   private DatagramPacketdp;

 

   public Receive(DatagramSocketds) {

      this.ds =ds;

   }

 

   @Override

   public void run() {

      while (true) {

         try {

            //接收发送到当前端口的数据

            byte[]buff = newbyte[1024];

            dp = new DatagramPacket(buff,buff.length);

            ds.receive(dp);

           

            //获取发送端Ip、端口号、内容等信息

            String ip = dp.getAddress().getHostAddress();

            intport = dp.getPort();

            String content = new String(dp.getData(), 0,dp.getLength());

            //打印信息到控制台

            System.out.println(ip +":" + port +":" + content);

           

            //如果接收到的信息是over,则关闭接收端

            if("over".equals(content)){

                System.out.println("关闭接收端");

                break;

            }

         } catch (Exceptione) {

            e.printStackTrace();

         }

      }

 

   }

}

 

3.TCP传输控制协议

面向连接,可靠的协议

需要建立连接,所以效率低

通过三次握手建立连接

 

Socket:客户端socket

ServerSocket:服务器socket

 

TCP是面向连接的、可靠的传输协议,如果在没有服务端的情况下,客户端发送数据,会抛错,这种情况是不允许的

代码示例

(1)发送数据到服务端并显示

 

/*

 * TCP实现客户端和服务端的收发过程

 *

 * 客户端的实现:发送信息到服务端,接收服务端返回的信息并显示

 */

public class TCPClient {

   public static void main(String[] args) throws Exception {

     

      System.out.println("客户端启动...");

      //创建客户端socket

      Socket client=new Socket("127.0.0.1",10086);

     

      //通过socket输出流发送数据

      OutputStream out=client.getOutputStream();

      out.write("服务器,你好".getBytes());

     

      //读取服务器返回的数据,通过socket输入流

      InputStream in=client.getInputStream();

      byte[] buf=new byte[1024];

      int len=in.read(buf);

      String content=new String(buf,0,len);

      System.out.println(content);

     

      //关闭资源

      client.close();

   }

}

 

/*

 * 服务器端:接收来自客户端的数据,并发送信息到客户端

 */

public class TCPServer {

   public static void main(String[] args) throws Exception {

      System.out.println("服务端启动");

     

      //创建服务端socket

      ServerSocket server=new ServerSocket(10086);

     

      //获取客户端

      Socket client=server.accept();

     

      //读取客户端数据

      InputStream in=client.getInputStream();

      byte[] buff=new byte[1024];

      int len=in.read(buff);

      String content=new String(buff,0,len);

      String ip=client.getInetAddress().getHostAddress();

      System.out.println(ip+":"+content);

     

      //给客户端发送数据

      OutputStream out=client.getOutputStream();

      out.write("你好,客户端".getBytes());

     

      //关闭资源

      client.close();

      //如果是不断的获取客户端,则不需要关闭服务端

      server.close();

   }

}

(2)客户端和服务器之间的频繁通信

   需求:

       客户端通过键盘录入发送数据到服务端

       服务端将接收到的数据显示到屏幕上的同时

       将这些数据转换成大写发往客户端

       当客户端输入over时,大写转换结束

注意:

   数据不刷新的话,因为缓冲区,数据没有被发到服务器端

   数据刷新后,数据可以被发到服务器端

   但是服务器端readLine中带有缓冲区,没有读到行终止符,就一直在阻塞状态

 

   方式1:手动加行终止符

      PrintWriter pw = newPrintWriter(out);

      pw.print(line+"\r\n");

      pw.flush();

   方式2:启用打印流的自动刷新

      PrintWriter pw = newPrintWriter(out,true);

      pw.println(line);

 

 

 

/*

 * 客户端:

 *     思路:

 *        1.创建客户端socket,明确地址和端口

 *        2.源:键盘录入,获取要转换的数据

 *        3.目的:网络,Socket输出流

 *        4.源:socket读取流,读取服务器发回来的大写数据

 *        5.目的:控制台,显示大写数据

 *        6.频繁的读写操作

 *        7.关闭资源

 *

*/

public class TCPClient {

   public static void main(String[] args) throws Exception {

 

      System.out.println("客户端运行");

 

      // 获取目的端ip

      InetAddress address = InetAddress.getByName("127.0.0.1");

 

      // 创建客户端socket

      Socket s = new Socket(address, 10086);

 

      // 获取键盘录入

      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

 

      // 获取socket读取流

      OutputStream out = s.getOutputStream();

      // BufferedWriter bout=newBufferedWriter(new OutputStreamWriter(out));

      PrintWriter pw = new PrintWriter(out);

 

      // 获取socket输出流

      InputStream in = s.getInputStream();

      BufferedReader bRead = new BufferedReader(new InputStreamReader(in));

 

      // 频繁的读写操作

      String line = null;

      while ((line =br.readLine()) != null) {

 

         pw.println(line); 

        

         if ("over".equals(line)) {

            break;

         }

        

         String upper = bRead.readLine();

         System.out.println(upper);

      }

 

      // 关闭资源

      br.close();

      s.close();

   }

}

 

/*

 * 服务端:

 *     思路:

 *        1.创建服务端socket,监听一个端口

 *        2.源:socket输入流,读取客户端发来的数据

 *        3.目的:socket输出流,将转成大写的数据发送给客户端

 *        4.频繁的读写资源

 *        5.关闭客户端

 */

public class TCPServer {

   public static void main(String[] args) throws Exception {

      System.out.println("服务端运行...");

      // 创建服务器socket

      ServerSocket ss =new ServerSocket(10086);

      while (true) {

         // 获取客户端对象

         Socket s = ss.accept();

        

         //打印客户端IP

         System.out.println(s.getInetAddress().getHostAddress()+"....connected");

         // socket输入流

         BufferedReader bin = new BufferedReader(new InputStreamReader(

                s.getInputStream()));

 

         // socket输出流

         PrintWriter pw = new PrintWriter(s.getOutputStream(),true);

 

         // 频繁的读写操作

         String line = null;

         while ((line =bin.readLine()) != null) {

            System.out.println(line);

            if("over".equals(line)){

                break;

            }

            // 转换大写,发送给客户端

            pw.println(line.toUpperCase());

            pw.flush();

         }

         s.close();

      }

   }

 

}

(3)TCP实现图片上传

/*

 * 客户端:上传图片到服务端,获取服务端发来的上传结果并显示

 */

public class Client {

   public static void main(String[] args) throws Exception {

      System.out.println("客户端启动...");

      // 创建客户端socket

      Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 10010);

      // 获取socket输出流

      BufferedOutputStream bos =new BufferedOutputStream(s.getOutputStream());

 

      // 读取要上传的文件

      BufferedInputStream bis =new BufferedInputStream(new FileInputStream(

            "D:\\1.jpg"));

      byte[] b = new byte[2048];

      int len;

      // 上传文件

      while ((len =bis.read(b)) != -1) {

         bos.write(b, 0,len);

      }

      // 向服务端发送了一个结束标记,让服务端结束读取的动作

      s.shutdownOutput();

      // 获取从服务器端发来的上传成功的信息

      InputStream in = s.getInputStream();

      byte[] b2 = new byte[1024];

      int len2 = in.read(b2);

      System.out.println(new String(b2, 0,len2));

 

      // 关闭资源

      bis.close();

      s.close();

 

      System.out.println("客户端关闭");

 

   }

}

 

/*

 * 服务端:接收客户端发送来的上传文件,存到指定目录中

 *         为防止出现同名覆盖,文件名=客户端ip+编号

 *         操作成功,发送上传成功到客户端

 */

public class Server {

   public static void main(String[] args) throws Exception {

      System.out.println("服务端启动..");

      // 创建服务器socket

      ServerSocket ss =new ServerSocket(10010);

      while (true) {

         // 获取客户端socket

         Socket s = ss.accept();

         //打印客户端IP

         String ip=s.getInetAddress().getHostAddress();

         System.out.println(ip+"...conneced");

         // 获取socket输入流

         BufferedInputStream bis =newBufferedInputStream(

                s.getInputStream());

        

         //新建File对象,指向目的文件夹

         File dir=new File("D:\\uploadTest");

         //目的文件夹不存在,则创建

         if(!dir.exists()){

            dir.mkdir();

         }

         //解决上传文件的重名覆盖问题

         int count=1;

         File desc=new File(dir,ip+"("+count+").jpg");

         while(desc.exists()){

            count++;

            desc=new File(dir,ip+"("+count+").jpg");

         }

        

         // 创建输出流,指向目的地址

         BufferedOutputStream bos =new BufferedOutputStream(

                new FileOutputStream(desc));

 

         // 复制文件

         byte[]b = newbyte[2048];

         int len;

         while ((len =bis.read(b)) != -1) {

            bos.write(b, 0,len);

         }

 

         // 向客户端发送上传成功的信息

         OutputStream out = s.getOutputStream();

         out.write("上传成功!".getBytes());

 

         // 关闭资源

         bos.close();

         s.close();

      }

   }

}

 

(4)多客户端并发上传

实现多客户端的并发上传,客户端代码不需变动,服务端必须启动多个线程来实现

 

/*

 * 客户端

 */

public class Client {

   public static void main(String[] args) throws Exception {

      System.out.println("客户端启动...");

      // 创建客户端socket

      Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 10010);

      // 获取socket输出流

      BufferedOutputStream bos =new BufferedOutputStream(s.getOutputStream());

 

      // 读取要上传的文件

      BufferedInputStream bis =new BufferedInputStream(new FileInputStream(

            "D:\\1.jpg"));

      byte[] b = new byte[2048];

      int len;

      // 上传文件

      while ((len =bis.read(b)) != -1) {

         bos.write(b, 0,len);

      }

      // 向服务端发送了一个结束标记,让服务端结束读取的动作

      s.shutdownOutput();

      // 获取从服务器端发来的上传成功的信息

      InputStream in = s.getInputStream();

      byte[] b2 = new byte[1024];

      int len2 = in.read(b2);

      System.out.println(new String(b2, 0,len2));

 

      // 关闭资源

      bis.close();

      s.close();

 

      System.out.println("客户端关闭");

 

   }

}

 

/*

 * 要想实现多个客户端并发上传,服务器必须启动多个线程来完成

 */

public class Server {

   public static void main(String[] args) throws Exception {

      System.out.println("服务端启动..");

      // 创建服务器socket

      ServerSocket ss =new ServerSocket(10010);

      while (true) {

         // 获取客户端socket

         Socket s = ss.accept();

        

         //将客户端socket封装进Upload,启动线程

         new Thread(new Upload(s)).start();

      }

   }

}

 

/*

 * 实现上传的方法

 */

public class Upload implements Runnable {

 

   private Sockets;

 

   public Upload(Sockets) {

      this.s =s;

   }

 

   @Override

   public void run() {

      try {

         // 打印客户端IP

         String ip = s.getInetAddress().getHostAddress();

         System.out.println(ip +"...conneced");

         // 获取socket输入流

         BufferedInputStream bis =newBufferedInputStream(

                s.getInputStream());

 

         // 新建File对象,指向目的文件夹

         File dir = new File("D:\\uploadTest");

         // 目的文件夹不存在,则创建

         if (!dir.exists()) {

            dir.mkdir();

         }

         // 解决上传文件的重名覆盖问题

         int count = 1;

         File desc = new File(dir,ip + "(" + count + ").jpg");

         while (desc.exists()) {

            count++;

            desc = new File(dir,ip + "(" + count + ").jpg");

         }

 

         // 创建输出流,指向目的地址

         BufferedOutputStream bos =new BufferedOutputStream(

                new FileOutputStream(desc));

 

         // 复制文件

         byte[]b = newbyte[2048];

         int len;

         while ((len =bis.read(b)) != -1) {

            bos.write(b, 0,len);

         }

 

         // 向客户端发送上传成功的信息

         OutputStream out = s.getOutputStream();

         out.write("上传成功!".getBytes());

 

         // 关闭资源

         bos.close();

         s.close();

      } catch (Exceptione) {

         e.printStackTrace();

      }

   }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员的tb_brand是指在JavaWeb基础教程中创建的一个表。这个表是用来存储品牌信息的,具体的表结构和数据类型需要和JavaBean类中的成员变量保持一致。\[1\]在这个教程中,使用了Maven来构建项目,并且使用了MyBatis作为持久层框架,通过配置pom.xml文件来引入相关依赖。\[2\] Maven是一个用于管理和构建Java项目的工具,它提供了一套标准化的项目结构、构建流程和依赖管理机制。\[3\] #### 引用[.reference_title] - *1* [【JAVAWEB开发】黑马程序员java web案例资料(含Element的删除与修改)](https://blog.csdn.net/aasd23/article/details/126940147)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [黑马程序员-MyBatis 框架-最全入门笔记、阿伟看了都得说真大、真细、真全!!!](https://blog.csdn.net/qq_57383364/article/details/128103058)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [JavaWeb——黑马程序员课程笔记](https://blog.csdn.net/King_ZACC/article/details/128573804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值