简述网络编程

导语

本文主要讲述关于网络编程的一些基本知识。每篇文章都在认真完成,如果文中有出错的地方还请各位及时指出,在下感激不尽。

概述

既然要说网络编程,那么什么是网络呢?简单点说,两台或者两台以上计算机就组成了网络。比如说我想通过 QQ 和你聊天,那么就会涉及到两个问题:第一,如何在众多电脑中找到你?;第二,找到你之后如何找到你的 QQ,然后和你聊天?

要解决这两个问题就需要两个东西:IP 地址和端口号。每台电脑都会有自己的 IP 地址,通过它来找到指定的电脑;每个程序又有自己的端口号,通过 IP 找到指定的电脑之后再通过端口号找到该电脑上指定的程序。

那么聊天过程中底层就会进行数据传输,数据传输肯定是有一定的规范、协议的,不能胡来吧,常见的协议有 TCP、UDP协议。

底层的数据传输的简图如下图所示:


数据传输.png

表面上看是在两台电脑间直接传输,实际过程如红线,经历了底层的实际数据传输过程。

那么底层的实际数据传输过程是怎样的呢?如下图所示:

底层传输.png

上图中的 ISO/OSI 参考模型又叫七层协议,只是理论理解,实际并没有得到应用。比如说电脑 1 的数据传输从上到下依次经过七层,数据到达电脑 2 之后又从下到上依次经过七层(如图数据传输)。

但是实际应用主要是左边的模型。每层都有自己的规则,传输层有 UDP、TCP 协议,网络层有 IP 协议,这是最主要的几个协议,所以这个模型又叫 TCP/IP 协议。这篇文章主要讲的就是传输层的 UDP、TCP 协议。

UDP、TCP 协议如下图:


UDP/TCP 协议.png
  • TCP 协议:如上图所示,比如说两个人打电话,电话1 要把数据传输给电话 2,那么数据可以选择不同的道路然后到达电话 2,也就是说条条大路通罗马。 有人把 TCP 协议称为三次握手,就是说,首先电话 1 把数据传给电话 2 (第一次握手),然后电话 2 再传数据给电话 1 告诉电话 1 我收到你的数据了(第二次握手),然后电话 1 再给电话 2 传数据告诉电话 2 我收到你反馈的数据了(第三次握手)。
  • UDP协议:比如说发短信,短信也是一条数据,UDP 协议就是说可以将数据分割成多份,每份独自进行传递,最后在目的地将分割的数据再收集起来。但是,UDP 有一个风险,就是分割之后的数据可能会存在走丢的情况,那么你发送的短信就存在对方收不到的风险。
TCP 协议 UDP 协议
优点 安全可靠 可靠性低
缺点 消耗资源,效率低 简单,开销小

1. InetAddress,InetSocketAddress

先讲两个类 InetAddress 和 InetSocketAddress。
InetAddress 封装的是 IP,先上代码:

1 public class TestInetAddress {
2   //InetAddress---IP 
3   public static void main(String[] args) throws UnknownHostException {
4   //创建一个InetAddress对象
5   //InetAddress ia=new InetAddress();//The constructor InetAddress() is not visible
6   //根本就没有构造器
7   //1.传入的是IP
8   InetAddress ia = InetAddress.getByName("192.168.1.250");
9   System.out.println("计算机名字:"+ia.getHostName());//计算机名
10   System.out.println("IP地址"+ia.getHostAddress());//IP地址
11   System.out.println(ia.getLocalHost());//计算机名和 IP 地址 
12   System.out.println("=================");
13   //2.传入计算机名
14  InetAddress ia2 = InetAddress.getByName("计算机名");
15  System.out.println("计算机名字:"+ia2.getHostName());//计算机名
16  System.out.println("IP地址"+ia2.getHostAddress());//IP 地址
17  System.out.println("=================");
18  //3.传入localhost
19  InetAddress ia3 = InetAddress.getByName("localhost");//相当于你传入本机的IP
20  System.out.println("计算机名字:"+ia3.getHostName());//localhost
21  System.out.println("IP地址"+ia3.getHostAddress());//本机的 IP 地址
22    }
23 }    

InetAddress 是一个类,如代码第 5 行所示,你如果想通过这种方式直接创建对象的话会有错误,The constructor InetAddress() is not visible,就是这个类根本就没有构造器。所以可以通过第 8 行的方式,调用 getByName() 方法,传进一个 IP 地址,然后这个方法会返回一个 InetAddress 类型的对象。getByName() 方法中可以传 IP 地址、计算机名、和 localhost(相当于传入本机的 IP 地址),然后通过产生的对象调用不同的方法得到相对应计算机的计算机名、IP 地址。

InetSocketAddress 可以传入 IP 地址和端口,代码如下:

1 //InetSocketAddress---可以支持IP,端口
2 InetSocketAddress isa=new InetSocketAddress("IP地址", 端口号);
3 System.out.println(isa.getHostName());//计算机名

InetSocketAddress 类可以直接创建对象然后传入 IP 地址和计算机名。

2. socket 套接字原理

如下图所示:

socket 原理(单向).png

原理(TCP 协议单向传递数据):

客户端:

  1. 首先会根据 Socket 类创建 Socket 对象,该对象指定服务器端的 IP 和端口号。
  • 然后应用层通过创建的 Socket 对象的输出流向对应的服务器端传递数据(因为已经给了 IP 地址和端口号)。传输层指定用什么协议传递 。

服务端:

  1. 会根据 ServerSocket 类创建 ServerSocket 对象,并给该对象传入一个端口号,这个端口号必须和客户端指定的端口号一致。
  • 然后该对象等待接收传递来的信息,接收成功以后会返回一个 Socket 类型的对象(相当于成功接收信息之后创建了一个 Socket 类型的对象)。
  • 然后服务器端通过该对象的输入流读取传递过来的数据。

这就是我个人理解的原理,理解了原理之后再写程序应该就没什么问题了。

3. 基于 TCP 的网络编程

注意:TCP的时候,必须先启动服务端,再启动客户端!!

3.1 单向通信

注意:本文中的代码实现的是用自己的电脑模拟两台计算机。
代码如下:

客户端:

1 public class TestClient {//客户端
2   public static void main(String[] args) throws UnknownHostException, IOException {
3       System.out.println("。。。客户端开始请求数据。。。");  
4       //1.Socket类指定服务器端的IP和端口号
5       Socket s=new Socket("192.168.1.250", 8888);
6       //2.创建输出流向外传送数据:
7       OutputStream os = s.getOutputStream();
8       DataOutputStream dos=new DataOutputStream(os);
9       dos.writeUTF("约吗?");
10     //3.关闭流
11     dos.close();
12     os.close();
13     s.close();
14  }
15 }

服务端:

1 public class TestServer { //服务器端
2   public static void main(String[] args) throws IOException {
3       System.out.println("服务器启动了。。。。");
4       //1.指定端口号:
5       ServerSocket ss=new ServerSocket(8888);
6       Socket s = ss.accept();//接收等待---阻塞状态
7       //2.创建输入流
8       InputStream is = s.getInputStream();
9       DataInputStream dis=new DataInputStream(is);
10     System.out.println("客户端对我说:"+dis.readUTF());
11     //3.关闭流
12     dis.close();
13     is.close();
14     ss.close();
15       s.close(); 
16  }
17 }

通过上面讲述的原理,然后再理解这两段代码应该没什么问题。如果有不理解的地方,对照着原理看代码,在此就不再赘述了。

3.2 双向通信

双向通信和单向通信本质上没什么区别,无非就是服务器端不仅能接收数据,还可以给客户端反馈数据;客户端不仅能发送数据,还能接收服务器端反馈回来的数据。

代码如下:

客户端:

1 public class TestClient {//客户端
2   public static void main(String[] args) throws UnknownHostException, IOException {
3        System.out.println("。。。客户端开始请求数据。。。");
4        //1.Socket类指定服务器端的IP和端口号
5        Socket s=new Socket("你自己的 IP 地址", 8888);
6        //2.我感受到的应用层  是一个输出流向外传送数据:
7        OutputStream os = s.getOutputStream();
8        DataOutputStream dos=new DataOutputStream(os);
9        dos.writeUTF("约吗?");
10      //3.接收服务器给的反馈:
11      InputStream is = s.getInputStream();
12      DataInputStream dis=new DataInputStream(is);
13      System.out.println("服务器端回应:"+dis.readUTF());
14      //4.关闭流
15      dos.close();
16      os.close();
17      s.close();
18  }
19 }

对比单向通信的客户端会发现,就多了一段接收服务器反馈数据的代码。而接收反馈的数据还是要用 Socket 对象的输入流来接收,然后再结合其他的 IO 流来读取数据。

服务端:

1 public class TestServer { //服务器端
2   public static void main(String[] args) throws IOException {
3        System.out.println("服务器启动了。。。。");
4        //1.指定端口号:
5        ServerSocket ss=new ServerSocket(8888);
6        Socket s = ss.accept();//接收等待---阻塞状态
7        //2.应用层感受到的是 你在操纵输入的流
8        InputStream is = s.getInputStream();
9        DataInputStream dis=new DataInputStream(is);
10      System.out.println("客户端对我说:"+s.getInetAddress().getHostAddress()+dis.readUTF());
11      //3.给客户端反应;
12      OutputStream os = s.getOutputStream();
13      DataOutputStream dos=new DataOutputStream(os);
14      dos.writeUTF("叔叔我们不约!");    
15      //4.关闭流
16      dis.close();
17      is.close();
18      ss.close();
19      s.close();
20  }
21 }

同样的,对比单向通信中服务端代码可知,多了一段给客户端反馈数据的代码。而反馈数据同样是利用 Socket 对象的输出流,然后再结合其他的 IO 流来输出反馈信息。

3.3 对象流传送

功能:客户端发送用户名和密码给服务端,服务端判断对错之后给客户端进行反馈。

先上代码,如下:

客户端:

1 public class TestClient {//客户端
2   public static void main(String[] args) throws UnknownHostException, IOException {
3        System.out.println("。。。客户端开始请求数据。。。");
4        //1.Socket类指定服务器端的IP和端口号
5        Socket s=new Socket("你的 IP 地址", 8888);
6        //2.创建输出流向外传送数据:
7        OutputStream os = s.getOutputStream();
8        ObjectOutputStream dos=new ObjectOutputStream(os);
9        Scanner sc=new Scanner(System.in);
10      System.out.print("请录入账号:");
11      String name=sc.next();
12      System.out.print("请录入密码:");
13      String password=sc.next();
14      dos.writeObject(new Person(name, password));
15      //3.接收服务器给的反馈:
16      InputStream is = s.getInputStream();
17      DataInputStream dis=new DataInputStream(is);
18      System.out.println("服务器端回应:"+dis.readUTF());
19      //4.关闭流
20      dos.close();
21      os.close();
22      s.close();
23      dis.close();
24      is.close();
25  }
26 }

代码第 9 行到第 13 行实现键盘录入的功能。第 14 行通过对象流把对象传递给服务器端。第 16 行到第 18 行接收服务器端的反馈信息。

服务端:

1 public class TestServer { //服务器端
2   public static void main(String[] args) throws IOException, ClassNotFoundException {
3        System.out.println("服务器启动了。。。。");
4        //1.指定端口号:
5        ServerSocket ss=new ServerSocket(8888);
6        Socket s = ss.accept();//接收等待---阻塞状态
7       //2.创建输入流接收数据
8        InputStream is = s.getInputStream();
9        ObjectInputStream dis=new ObjectInputStream(is);
10      Person p =(Person)dis.readObject();//向下转型
11      //3.给客户端反应;
12      OutputStream os = s.getOutputStream();
13      DataOutputStream dos=new DataOutputStream(os);
14      //加入对用户的账号和密码进行校验
15      if(p.getName().equals("lili")&&p.getPassWord().equals("1919")){
16          dos.writeUTF("登陆成功!");
17      }else{
18          dos.writeUTF("用户名或者密码不正确,登陆失败!");       
19      }
20      //4.关闭流
21      dis.close();
22      is.close();
23      ss.close();
24      s.close();
25      dos.close();
26      os.close(); 
27  }
28 }

代码第 10 行向下转型,将 Object 类型转化为 Person 类型的数据。第 15 行到第 19 行是对传进来的 Person 对象进行校验并给客户端反馈信息。

4. 基于 UDP 的网络编程

注意啦:

  • TCP 的时候,必须先启动服务器,再启动客户端。但是在 UDP 中并不是这样。
  • UDP 没有客户端和服务器的概念,只有发送方和接收方。
  • UDP通信机制:通过数据包(又称数据报)来传递数据。
  • 两个最重要的类:(1)DatagramSocket 此类用来发送和接收数据包的套接字;(2)DatagramPacket 此类表示数据包。

另外,

UDP 中不涉及 IO 流!
UDP 中不涉及 IO 流!
UDP 中不涉及 IO 流!

重要的事情说三遍。

原理(UDP 协议单向传递数据):

发送方:

  1. 创建套接字DatagramSocket(DatagramSocket ds=new DatagramSocket(xxxx);
    ),然后给套接字对象传入一个端口号,这个端口号是发送方的端口号!
  2. 创建数据包:封装要发送的信息,IP,端口(接收方的端口)等(详见后面代码);
  3. 通过套接字将数据包传出去。
  4. 关闭套接字。

接收方:

  1. 创建套接字 DatagramSocket (DatagramSocket ds=new DatagramSocket(xxxx);),给套接字对象传入接收方的端口号。
  2. 创建数据包;
  3. 套接字对象将发送方传过来的东西接收到这个空的数据包中;
  4. 关闭套接字。

另外需要说的地方就是,与 TCP 不同,在UDP中可以先启动发送方,但是可能会出现丢包现象,就是一部分数据可能会丢失。

4.1 单向通信

代码如下:

发送方:

1 public class TestSend {//发送方
2   public static void main(String[] args) throws IOException {
3        System.out.println("发送方。。。。");
4        //1.创建套接字DatagramSocket---是发送方的端口
5        DatagramSocket ds=new DatagramSocket(8888);
6        //在这里可以指定发送方的端口号是8888,假如我不指定的话,那么会随机在我机器中不用的端口号中随机选择一个作为我发送方的端口。
7        //2.创建数据包:封装我要发送的信息,IP,端口等
8        String str="hello";
9        byte[] b = str.getBytes();
10      DatagramPacket dp=new DatagramPacket(b, b.length, InetAddress.getByName("localhost"), 9999);
11      //3.通过套接字将数据包传出去
12      ds.send(dp);
13      //4.关闭套接字
14      ds.close();
15  }
16 }

接收方:

1 public class TestReceive {//接收方
2   public static void main(String[] args) throws IOException {
3        System.out.println("接收方。。。。");
4        //1.创建套接字 DatagramSocket --接收---接收方的端口号指定为9999
5        DatagramSocket ds=new DatagramSocket(9999);    
6        //2.创建数据包
7        byte[] b=new byte[1024];
8        DatagramPacket dp=new DatagramPacket(b, b.length);
9        //3.将发送方传过来的东西接收到这个空的数据包中
10      ds.receive(dp);
11      //4.查看接收的信息
12        System.out.println("发送方说:"+new String(dp.getData(),0,dp.getLength()));        
13        //5.关闭套接字
14        ds.close();
15  }
16 }

参考上面的原理来理解这两段代码,其实都是按照上面说的步骤来的,没什么好讲解的地方吧。

4.2 双向通信

双向通信和单向通信本质上也没什么区别,无非就是接收方不仅能接收数据,还可以给发送方反馈数据;发送方不仅能发送数据,还能接收接收方端反馈回来的数据。

发送方:

1 public class TestSend {//发送方
2   public static void main(String[] args) throws IOException {
3        System.out.println("发送方。。。。");
4        //1.创建套接字DatagramSocket---是发送方的端口
5        DatagramSocket ds=new DatagramSocket(8888);
6        //我在这里可以指定发送方的端口号是8888,假如我不指定的话,那么会随机在我机器中不用的端口号中随机选择一个作为我发送方的端口。
7        //2.创建数据包:封装我要发送的信息,IP,端口等
8        System.out.print("学生说:");
9        Scanner sc=new Scanner(System.in);
10      String str=sc.next();
11      byte[] b = str.getBytes();
12      DatagramPacket dp=new DatagramPacket(b, b.length, InetAddress.getByName("localhost"), 9999);
13      //3.通过套接字将数据包传出去
14      ds.send(dp);
15      //4.接收 接收方 的信息
16      byte[] b1=new byte[1024];
17      DatagramPacket dp1=new DatagramPacket(b1, b1.length);
18      ds.receive(dp1);
19        System.out.println("老师说:"+new String(dp1.getData(),0,dp1.getLength()));       
20      //5.关闭套接字
21      ds.close();
22  }
23 }

与单向通信相比,多了第 16 行到第 19 行代码,创建数据包,套接字对象将接收方传过来的东西接收到这个空的数据包中,使发送方具备了接收的功能。

接收方:

1 public class TestReceive {//接收方
2   public static void main(String[] args) throws IOException {
3        System.out.println("接收方。。。。");
4        //1.创建套接字 DatagramSocket --接收---接收方的端口号指定为9999
5        DatagramSocket ds=new DatagramSocket(9999);
6        //2.创建数据包
7        byte[] b=new byte[1024];
8        DatagramPacket dp=new DatagramPacket(b, b.length);
9        //3.将发送方传过来的东西接收到这个空的数据包中
10      ds.receive(dp);
11      //4.查看接收的信息
12        System.out.println("学生说:"+new String(dp.getData(),0,dp.getLength()));     
13        //5.给发送方进行回复
14        System.out.print("老师说:");
15        Scanner sc=new Scanner(System.in);
16        String str=sc.next();
17      byte[] b1 = str.getBytes();
18      DatagramPacket dp1=new DatagramPacket(b1, b1.length, InetAddress.getByName("localhost"), 8888);
19      ds.send(dp1); 
20        //6.关闭套接字
21        ds.close();
22  }
23 }

代码第 14 行至第 16 行是程序具备了键盘录入的功能,不属于新知识点。第 17 行至第 19 行创建数据包封装要反馈的信息,IP,端口(发送方的端口)等(第 18 行),然后通过套接字将数据包传出去(第 19 行)。


网络编程就先写到这儿,欢迎补充。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编...
    程序员欧阳阅读 1,998评论 1 37
  • 计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。 按照计算机网络的定义,通过一定...
    蛋炒饭_By阅读 1,209评论 0 10
  • 一、网络通信协议 定义:对数据的传输格式、传输效率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换,...
    聂叼叼阅读 495评论 0 2
  • 1. 网络编程概述 1.1 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接...
    JackChen1024阅读 1,028评论 0 3
  • 晶莹,剔透, 宁静似那冷傲, 深奥的海洋。 无力对抗, 堕进一片蓝蓝的思海, 人全身放松的躺着, 浮泊于这深深的蓝...
    我是晓晓阅读 323评论 0 0