企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## Java网络编程 ### java网络编程基础知识 ### 1、协议(TCP/IP)     TCP/IP(Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。 ### TCP/IP协议的由来     在阿帕网(ARPR)产生运作之初,通过接口信号处理机实现互联的电脑并不多,大部分电脑相互之间不兼容,在一台电脑上完成的工作,很难拿到另一台电脑上去用,想让硬件和软件都不一样的电脑联网,也有很多困难。当时美国的状况是,陆军用的电脑是DEC系列产品,海军用的电脑是Honeywell中标机器,空军用的是IBM公司中标的电脑,每一个军种的电脑在各自的系里都运行良好,但却有一个大弊病:不能共享资源。   ### 互联网之父--瑟夫(Vinton G.Cerf) 1997年,为了褒奖对因特网发展作出突出贡献的科学家,并对TCP/IP协议作出充分肯定,美国授予为因特网发明和定义TCP/IP协议的文顿·瑟夫和卡恩“国家技术金奖”。这无疑使人们认识到TCP/IP协议的重要性。 ![](https://box.kancloud.cn/2016-02-25_56ceb3e408e4b.jpg) ### tcp/ip基础--ip地址与包的路由传递 ip地址 概述:每个internet上的主机和路由器都有一个ip地址,它包括网络号和主机号,所有ip地址都是32位的,ip地址按照国际标准的划分为a,b,c,d,e五种类型。   ### 端口(port)--概念     在网络技术中,端口(Port)有好几种意思。集线器、交换机、路由器的端口指的是连接其他网络设备的接口,如RJ-45端口、Serial端口等。这里所指的端口不是指物理意义上的端口,而是特指TCP/IP协议中的端口,是逻辑意义上的端口。     如果把IP地址比作一间房子,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口可以有65536(即:256*256)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0到65535(256*256-1)。   ### 端口(port)--分类 有65536个端口0号是保留端口 1-1024是固定端口 又叫有名端口,即被某些程序固定使用,一般程序员不使用。 22:SSH远程登录协议 23:telnet使用 21:ftp使用 25:smtp服务使用 80:iis使用 7:echo服务 1025-65535是动态端口 这些端口,程序员可以使用   ### 端口(port)--注意事项 1、在计算机(尤其是做服务器)要尽可能的少开端口; 2、一个端口只能被一个程序监听; 3、如果使用netstat -an可以查看本机有哪些端口在监听 4、可以使用netstat -anb来查看监听端口的pid,在结合任务管理器关闭不需要的端口。   ### url--概念     统一资源定位符(URL,Uniform Resource Locator的缩写)也被称为网页地址,是因特网上标准的资源的地址。它最初是由蒂姆·伯纳斯-李发明用来作为万维网的地址的。现在它已经被万维网联盟编制为因特网标准RFC1738了。     Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL地址,这种地址可以是本地磁盘,也可以是局域网上的某一台计算机,更多的是Internet上的站点,简单地说,URL就是Web地址,俗称“网址”,是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。   ### url--组成 http://www.sina.com:8080/index.html 1、协议;2、ip地址(32位);3、端口号(16位)0-65535;4、资源名称。   ### 单工、半双工和全双工     如果甲可以向乙发送数据,但是乙不能向甲发送数据,这样的通信就是单工通信(Simplex Communication)。     单工数据传输只支持数据在一个方向上传输,就和传呼机一样。     半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信,就和对讲机一样; 全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力,就和电话一样。 ![](https://box.kancloud.cn/2016-02-25_56ceb3e418941.jpg) #### #### 案例一:半双工 ##### Server1.java ~~~ /** * 半双工 * 服务器端,9999端口监听 * 可以接收从客户端发来的信息 */ package com.net.server; import java.io.IOException; import java.net.*; import java.io.*; public class Server1 { ServerSocket ss = null; Socket s = null; // 构造方法 public Server1() { try { // 在9999端口进行监听 ss = new ServerSocket(9999); // 等待某个客户端来连接,该方法会返回一个Socket连接 s = ss.accept(); // 读取s中传递的数据 InputStreamReader isr = new InputStreamReader(s.getInputStream()); BufferedReader br = new BufferedReader(isr); String info = br.readLine(); System.out.println("服务器接收到了" + info); PrintWriter pw = new PrintWriter(s.getOutputStream(), true); pw.println("Hello,Client!"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (s != null) { s.close(); } if (ss != null) { ss.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Server1 s1 = new Server1(); } } ~~~ ##### Client1.java ~~~ /** * 客户端 */ package com.net.client; import java.io.IOException; import java.net.*; import java.io.*; public class Client1 { Socket s = null; //构造方法 public Client1(){ try { //Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,9999是该服务器的端口号 s = new Socket("127.0.0.1", 9999); //连接成功,就可以发送数据给服务器 //通过PrintWriter向s写数据,true表示即时刷新 PrintWriter pw = new PrintWriter(s.getOutputStream(), true); pw.println("Hello,Server!"); InputStreamReader isr = new InputStreamReader(s.getInputStream()); BufferedReader br = new BufferedReader(isr); String resp = br.readLine(); System.out.println("客户端接收到了" + resp); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if(s != null){ s.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Client1 c1 = new Client1(); } } ~~~ #### 案例二:半双工聊天 ##### Server2.java ~~~ /** * 半双工 * 服务器端,9999端口监听 * 可以接收从客户端发来的信息 */ package com.net.server; import java.net.*; import java.io.*; public class Server2 { ServerSocket ss = null; Socket s = null; BufferedReader br1 = null; BufferedReader br2 = null; PrintWriter pw = null; // 构造方法 public Server2() { try { // 在9999端口进行监听 ss = new ServerSocket(9999); // 等待某个客户端连接,返回 Socket s = ss.accept(); while (true) { // 从客户端接收消息 br1 = new BufferedReader(new InputStreamReader( s.getInputStream())); String str = br1.readLine(); System.out.println("从客户端收到的消息是:" + str); // 如果收到消息为"byebye",关闭服务器 if (str.equals("byebye")) { System.out.println("服务器关闭连接"); break; } // 从控制台输入 System.out.print("从控制台输入:"); br2 = new BufferedReader(new InputStreamReader(System.in)); // 将消息发送给客户端 pw = new PrintWriter(s.getOutputStream(), true); pw.println(br2.readLine()); } } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭资源 if (pw != null) { pw.close(); } if (br2 != null) { br2.close(); } if (br1 != null) { br1.close(); } if (s != null) { s.close(); } if (ss != null) { ss.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Server2 s2 = new Server2(); } } ~~~ ##### Client2.java ~~~ /** * 客户端 */ package com.net.client; import java.net.*; import java.io.*; public class Client2 { Socket s = null; PrintWriter pw = null; BufferedReader br1 = null; BufferedReader br2 = null; public Client2() { try { // Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,9999是该服务器的端口号 s = new Socket("127.0.0.1", 9999); while (true) { // 连接成功,就可以发送数据给服务器 // 从控制台读入数据 System.out.print("从控制台输入:"); br1 = new BufferedReader(new InputStreamReader(System.in)); String str = br1.readLine(); // 通过PrintWriter向s写数据,true表示即时刷新 pw = new PrintWriter(s.getOutputStream(), true); pw.println(str); if (str.equals("byebye")) { System.out.println("客户端关闭连接"); break; } // 从服务端接收消息 br2 = new BufferedReader(new InputStreamReader( s.getInputStream())); System.out.println("从服务器接收的消息是:" + br2.readLine()); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { // 关闭资源 if (pw != null) { pw.close(); } if (br2 != null) { br2.close(); } if (br1 != null) { br1.close(); } if (s != null) { s.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Client2 c2 = new Client2(); } } ~~~ #### 案例三:全双工聊天 ##### Server3.java ~~~ /** * 全双工 * 监听端口6166 */ package com.net.server; import java.net.*; import java.io.*; import java.awt.*; import java.awt.RenderingHints.Key; import javax.swing.*; import java.awt.event.*; public class Server3 extends JFrame implements ActionListener, KeyListener { // 网络变量 ServerSocket ss = null; Socket s = null; // IO流 BufferedReader br = null; PrintWriter pw = null; // 定义组件 JTextArea jta = null; JTextField jtf = null; JButton jb = null; JPanel jp1 = null; JScrollPane jsp = null; // 构造方法 public Server3() { // 创建组件 jta = new JTextArea(); jsp = new JScrollPane(jta); jtf = new JTextField(20); jtf.addKeyListener(this); jb = new JButton("发送"); jb.addActionListener(this); jp1 = new JPanel(); // 添加到JPanel jp1.add(jtf); jp1.add(jb); // 添加到JFrame add(jsp, "Center"); add(jp1, "South"); // 设置窗体 setTitle("服务器端"); setSize(400, 300); setLocation(0, 100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); try { // 服务器监听 ss = new ServerSocket(6166); // 等待客户端连接 s = ss.accept(); // 创建读入缓冲字符流 br = new BufferedReader(new InputStreamReader(s.getInputStream())); // 创建打印流 pw = new PrintWriter(s.getOutputStream(), true); while (true) { // 读取从客户端发来的信息 // 当没有消息过来时,会一直处于阻塞状态,这条语句也就不会执行 String info = br.readLine(); jta.append("客户端:" + info + "\r\n"); } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { Server3 s3 = new Server3(); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == jb) { // 点击确定,发送信息 // 把服务器在jtf写的内容发送给客户端,并在jta显示 String info = jtf.getText(); pw.println(info); jta.append("服务器:" + info + "\r\n"); jtf.setText(""); } } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub if (e.getKeyCode() == KeyEvent.VK_ENTER) { // 按下Enter,发送信息 // 把服务器在jtf写的内容发送给客户端,并在jta显示 String info = jtf.getText(); pw.println(info); jta.append("服务器:" + info + "\r\n"); jtf.setText(""); } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } } ~~~ ##### Client3.java ~~~ /** * 客户端 */ package com.net.client; import java.net.*; import java.io.*; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Client3 extends JFrame implements ActionListener, KeyListener { // 网络变量 Socket s = null; // IO流 BufferedReader br = null; PrintWriter pw = null; // 定义组件 JTextArea jta = null; JTextField jtf = null; JButton jb = null; JPanel jp1 = null; JScrollPane jsp = null; // 构造方法 public Client3() { // 创建组件 jta = new JTextArea(); jsp = new JScrollPane(jta); jtf = new JTextField(20); jtf.addKeyListener(this); jb = new JButton("发送"); jb.addActionListener(this); jp1 = new JPanel(); // 添加到JPanel jp1.add(jtf); jp1.add(jb); // 添加到JFrame add(jsp, "Center"); add(jp1, "South"); // 设置窗体 setTitle("客户端"); setSize(400, 300); setLocation(500, 100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); try { // Socket()方法可以连接某个服务器,127.0.0.1表示服务器的IP,6166是该服务器的端口号 s = new Socket("127.0.0.1", 6166); // 创建读入缓冲字符流 br = new BufferedReader(new InputStreamReader(s.getInputStream())); // 创建打印流 pw = new PrintWriter(s.getOutputStream(), true); while (true) { // 读取从服务器发来的消息 // 当没有消息过来时,会一直处于阻塞状态,这条语句也就不会执行 String info = br.readLine(); jta.append("服务器:" + info + "\r\n"); } } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭资源 if (pw != null) { pw.close(); } if (br != null) { br.close(); } if (s != null) { s.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Client3 c3 = new Client3(); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == jb) { // 如果点击确定按钮 // 发送给服务端,并更新jtf,并在jta显示 String info = jtf.getText(); pw.println(info); jta.append("客户端:" + info + "\r\n"); jtf.setText(""); } } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub if (e.getKeyCode() == KeyEvent.VK_ENTER) { // 按下Enter,发送信息 // 把服务器在jtf写的内容发送给客户端,并在jta显示 String info = jtf.getText(); pw.println(info); jta.append("服务器:" + info + "\r\n"); jtf.setText(""); } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } } ~~~   #### 案例四:在网络间传递对象 ##### User.java ~~~ /** * 对象流所用对象 * 必须序列化 */ package com.objectstream; import java.io.*; public class User implements Serializable { private String name; private String pass; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } } ~~~ ##### Server1.java ~~~ /** * 对象流 * 服务器 * 监听端口1234 */ package com.objectstream; import java.net.*; import java.io.*; public class Server1 { ServerSocket ss = null; Socket s = null; ObjectInputStream ois = null; // 构造方法 public Server1() { try { ss = new ServerSocket(1234); s = ss.accept(); System.out.println("在1234端口监听"); // 以对象流方式读取(假定客户端发送的是User的一个对象) ois = new ObjectInputStream(s.getInputStream()); User u = (User) ois.readObject(); // 输出 System.out.println("从客户端接收到了" + u.getName() + " " + u.getPass()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (ois != null) { ois.close(); } if (s != null) { s.close(); } if (ss != null) { ss.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { Server1 s1 = new Server1(); } } ~~~ ##### Client1.java ~~~ /** * 客户端 */ package com.objectstream; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client1 { Socket s = null; ObjectOutputStream oos = null; // 构造方法 public Client1() { try { s = new Socket("127.0.0.1", 1234); // 通过ObjectOutputStream给服务器传递对象 oos = new ObjectOutputStream(s.getOutputStream()); User u = new User(); u.setName("张三"); u.setPass("123456"); oos.writeObject(u); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (oos != null) { oos.close(); } if (s != null) { s.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { Client1 c1 = new Client1(); } } ~~~ 特别说明: 在java网络编程要通过IO流实现对象的传递,需要对服务端和客户端定义相同的对象,以达到实现对象的传递。同时需要类进行Serializable序列化,否则报错。 ----------参考《韩顺平.循序渐进学.java.从入门到精通》 ----------参考《JDK_API_1_6_zh_CN》 Java学习笔记--导航[http://blog.csdn.net/q547550831/article/details/49819641](http://blog.csdn.net/q547550831/article/details/49819641)