Java Socket网络编程

网络编程概述
 
  计算机网络:
  是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
 
  网络编程:
  就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
 
  网络模型:
  计算机网络之间以何种规则进行通信,就是网络模型研究问题。
  网络模型一般是指
       OSI(Open System Interconnection开放系统互连)参考模型
       TCP/IP参考模型
 
 
  网络模型7层(应表会传网数物)概述:
  1、物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
  2、数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
  3.、网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
  4.、传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
  5、会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
  6、表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
  7、应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。
 
 
 
  网络编程三要素:
  A:IP地址
    a:点分十进制 (用点号分隔的十进制数据)
    b:IP地址的组成 (网络号段+主机号段)
    c:IP地址的分类 ()
    d:dos命令
    e:InetAddress
  B:端口
          是应用程序的标识。范围:0-65535。其中0-1024不建议使用(系统保留)。
  C:协议
    UDP:数据打包,有限制,不连接,效率高,不可靠
    TCP:建立数据通道,无限制,效率低,可靠
 
  ip地址的介绍
    A:所谓IP地址就是给每个连接在Internet上的主机分配的一个32bit地址。
    按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,比特换算成字节,就是4个字节。例如一个采用二进制形式的IP地址是“00001010000000000000000000000001”,这么长的地址,人们处理起来也太费劲了。为了方便人们的使用,IP地址经常被写成十进制的形式,中间使用符号“.”分开不同的字节。于是,上面的IP地址可以表示为“10.0.0.1”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多。
 
    B:IP地址的组成
      IP地址 = 网络号码+主机地址
 
    A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码(主机号段)
         一个网络号有:256*256*256=16777216个ip地址
    B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
         一个网络号有:256*256=65536个ip地址
    C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
         一个网络号有:256个ip地址
 
    特殊地址:
    127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1
 
    DOS命令 ipconfig:查看本机IP地址
 
      xxx.xxx.xxx.0 网络地址
      xxx.xxx.xxx.255 广播地址
 
    A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.X.X.X是保留地址,用做循环测试用的。
    B类 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
    C类 192.0.0.1---223.255.255.254 192.168.X.X是私有地址
    D类 224.0.0.1---239.255.255.254
    E类 240.0.0.1---247.255.255.254
 
 
    那么,我们如果获取和操作IP地址呢?
      为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress 供我们使用。
      InetAddress类没有构造方法。
    问题:
         如果一个类没有构造方法:
      1.成员全是静态的(Math,Arrays,Collections);
      2.单例设计模式(Runtime)
      3.类中有静态方法返回该类的对象(InetAddress)。
 
  端口号
    物理端口 网卡口
    逻辑端口 我们指的就是逻辑端口
      A:每个网络程序都会至少有一个逻辑端口
      B:用于标识进程的逻辑地址,不同进程的标识
      C:有效端口:0~65535,其中0~1024系统使用或保留端口。
 
 网络IO
    网络IO即网络中的输入与输出。在正常的网络通信中,一条消息发送的过程中有个很重要的媒介,即网卡,它的作用有:
      ①:将电脑的数据封装为帧,通过网线(对无线网络来说就是电磁波)将数据发送到网络上去
      ②:接收网络上其他设备传过来的帧,并将帧重新组合成数据,发送到所在的电脑中

    网卡能「接收所有在网络上传输的信号」,但正常情况下只接受发送到该电脑的帧和广播帧,将其余的帧丢弃。

    所以网络 I/O 其实网络与服务端(电脑内存)之间的输入与输出

  
 
 
 
Socket
  什么是Socket?
       网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
    Socket本质是操作系统提供给通信层的一组抽象API接口(不是程序也不是协议),用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信
    Socket套接字是对TCP/IP协议的封装,自身并非协议而是一套调用的接口规范(API)。通过套接字Socket,才能使用TCP/IP协议
    Socket的含义就是两个应用程序通过一个双向的通信连接实现数据的交换,连接的一段就是一个socket,又称为套接字。实现一个socket连接通信至少需要两个套接字,一个运行在服务端(插孔),一个运行在客户端(插头)
    
 
  Socket原理机制:
    通信的两端都有Socket。
    网络通信其实就是Socket间的通信。
    数据在两个Socket间通过IO传输。
 
  
  基于TCP的Socket运行流程:
 
    
    Server:
      socket():表示创建一个 socket,底层会生成一个文件描述符,用来表示该 socket
      bind():用来绑定服务的端口,地址,这里一般都是以固定的为主,因为在客户端连接的时候需要指定
      listen():当端口绑定完成之后,listen 就会监听这个端口的数据包
      accept():阻塞等待连接请求。相当于一个开关,表示我准备好了,可以接受请求了,但是这里会一直阻塞,直到客户端连接成功
      read():读取客户端发送过来的内容
      write():客户端写入要返回的数据
      close():断开连接,「四次挥手」
 
    Client:
      socket():表示创建一个 socket,底层会生成一个文件描述符,用来表示该 socket
      connet():表示与指定地址进行连接,在此之前,会随机创建自己的端口,tcp 的「三次握手就是从这里开始」
      write():客户端写入要发送的数据
      read():客户端读取服务端返回的数据
      close():断开连接,「四次挥手」,给客户端发送断开连接的信息
 
 
    三次握手发生在 socket 的哪几个函数中?
      ①:当客户端调用 connect 时,触发了连接请求,向服务器发送了SYN 信号,这时 connect 进入阻塞状态;
      ②:服务器监听到连接请求,即收到 SYN,调用 accept 函数接收,进入阻塞状态,在此之前会尽力 socket、bind、listen 函数;然后返回相关的 syn 以及 ack 信号
      ③:客户端接受到服务端的信息,此时 connect 完成,解除阻塞状态,并且向服务端发送 ack 信号
      ④:服务端收到 ack, accept 阻塞解除,完成连接
      
      
 
 
UDP和TCP协议
 
  UDP
    将数据源和目的封装成数据包中,不需要建立连接;每个数据报的大小在限制在64k;因无连接,是不可靠协议;不需要建立连接,速度快
    特点:
      把数据打包
      数据有限制
      不建立连接
      速度快
      不可靠
    如:发短信,qq聊天
 
  TCP
    建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低
    特点:
      建立连接通道
      数据无限制
      速度慢
      可靠
    如:打电话
 
 
 

  UDP协议通过Socket发送数据:
    步骤:
      1、创建发送端的Socket对象
      2、创建数据,并把数据打包
      3、调用Socket对象的发送方法发送数据
      4、释放资源

package com.yang.net.socket01;

import java.io.IOException;
import java.net.*;

/**
 * UDP协议发送数据
 * 1、创建发送端的socket对象
 * 2、创建数据,并把数据打包
 * 3、调用socket对象的发送方法发送数据包
 * 4、释放资源
 * Created by Yang on 2017/8/27.
 */
public class SendDemo {
    public static void main(String[] args) throws IOException {
        //1、创建发送端的socket对象
        DatagramSocket ds = new DatagramSocket();
        //2、创建数据,并把数据打包
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
        //字节数组
        byte[] buf = "nihao,udp我来了!".getBytes();
        //长度
        int length = buf.length;
        //要发送到的ip地址
        InetAddress inetAddress = InetAddress.getByName("192.168.1.146");
        //端口号,自己指定,建议10000以上
        int port = 10000;

        //3、调用socket对象的发送方法发送数据包
//        send(DatagramPacket p)
//        从此套接字发送数据报包。
        ds.send(new DatagramPacket(buf, length, inetAddress, port));
        //4、释放资源
        ds.close();
    }

}

 

  UDP协议通过Socket接收数据:
    步骤:
       1、创建接收端的socket对象,指定端口
       2、创建一个数据包(接收容器)
       3、调用socket对象的接收方法接收数据包
       4、解析数据包,显示在控制台
       5、释放资源
package com.yang.net.socket01;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * UDP协议接收数据
 * 1、创建接收端的socket对象,指定端口
 * 2、创建一个数据包(接收容器)
 * 3、调用socket对象的接收方法接收数据包
 * 4、解析数据包,显示在控制台
 * 5、释放资源
 * Created by Yang on 2017/8/27.
 */
public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        //1、创建接收端的socket对象,指定端口
        DatagramSocket ds=new DatagramSocket(10000);
        //2、创建一个数据包(接收容器)
        /* DatagramPacket(byte[] buf, int length)
          构造 DatagramPacket,用来接收长度为 length 的数据包。*/
        //接收的字节数组
        byte[] bys=new byte[1024];
        int len=bys.length;
        DatagramPacket dp=new DatagramPacket(bys,len);
        //3、调用socket对象的接收方法接收数据包
        //阻塞式,直到接收到数据
        ds.receive(dp);
        //4、解析数据包,显示在控制台
        //发送方的ip地址
        InetAddress inetAddress=dp.getAddress();
        String ip=inetAddress.getHostAddress();
        byte[] bytes=dp.getData();
        //获取接收到的长度
        int length=dp.getLength();
        String s=new String(bytes,0,length);
        System.out.println(ip+"--"+s);
        //5、释放资源
        ds.close();
    }
}

    注意:要先运行接收端,再运行发送端,接收端等待发送端发送数据然后接收数据。

 

 

  TCP协议接收数据:

package com.yang.net.socket01;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * TCP协议接收数据
 * 1、创建接收端的Socket对象(ServerSocket)
 * 2、监听客户端连接,返回一个对应的Socket对象
 * 3、获取输入流,读取数据显示在控制台
 * 4、释放资源
 * Created by Yang on 2017/8/28.
 */
public class SerSocket {
    public static void main(String[] args) throws IOException {
        //1、创建接收端的Socket对象(ServerSocket)
        //ServerSocket(int port)    创建绑定到特定端口的服务器套接字,此方法在连接之前一直阻塞
        ServerSocket serverSocket = new ServerSocket(10010);

        //2、监听客户端连接,返回一个对应的Socket对象
        Socket socket = serverSocket.accept();

        //获取客户端的ip地址
        String ip = socket.getInetAddress().getHostAddress();

        //3、获取输入流,读取数据显示在控制台
        InputStream is = socket.getInputStream();
        byte[] bys = new byte[1024];
        /*int len = -1;
        while ((len = is.read(bys)) != -1) {
            String s = new String(bys, 0, len);
            System.out.println(ip + "--" + s);
        }*/
        int len = is.read(bys);
        String s = new String(bys, 0, len);
        System.out.println(ip + "--" + s);

        //反馈给客户端信息
        OutputStream os = socket.getOutputStream();
        os.write("数据已经收到".getBytes());

        //释放资源
        socket.close();
        //服务器不用关
        //serverSocket.close();
    }
}

 

  TCP协议发送数据:

package com.yang.net.socket01;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * TCP协议发送数据
 * 1、创建发送端的Socket对象
 * 这一步如果成功,就说明连接已经成功建立了
 * 2、获取输出流,写数据
 * 3、释放资源
 * Created by Yang on 2017/8/28.
 */
public class ClientSocket {
    public static void main(String[] args) throws IOException {
        // 1、创建发送端的Socket对象
        // Socket(String host, int port)
        // 创建一个流套接字并将其连接到指定主机上的指定端口号。
        Socket socket = new Socket("192.168.1.146", 10010);

        // 2、获取输出流,写数据
        //getOutputStream() 返回此套接字的输出流。
        OutputStream os = socket.getOutputStream();
        os.write("Hello,TCP,我来了".getBytes());

        //获取服务端的反馈
        InputStream is = socket.getInputStream();//阻塞式方法
        byte[] bytes = new byte[1024];
        /*int len = -1;
        while ((len = is.read(bytes)) != -1) {
            String s = new String(bytes, 0, len);
            System.out.println(s);
        }*/
        int len = is.read(bytes);
        String s = new String(bytes, 0, len);
        System.out.println(s);
        
        //3、释放资源
        socket.close();
    }
}

 

 
 

END.

 
posted @ 2021-03-31 16:10  杨岂  阅读(86)  评论(0编辑  收藏  举报