Java网络编程总结

网络编程的基础概念

1.端口

用来标识计算机上的网络应用程序,端口是一个虚拟的概念,是16位二进制正整数,故取值为0-65535(十进制)。端口一共可以在一台计算机上存在12w+(2^17)个,因为端口属于传输层,传输层有两个重要协议(TCP和UDP),所以两边各65536个(2^16)。一般来说端口够用,因为计算机上用不到12w多个网络应用。

 端口0-1023为知名端口,也叫公认端口,端口1023-49151为注册端口, 比如3306(MySQL),8080(Tomcat),端口49152-65535为动态端口或者私有端口。

Windows查看所有使用的端口: cmd下

netstat -ano

 

2.ip地址

IP地址是网络中设备的唯一标识,IP地址分为两大类

  • IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址的长32bit,也就是4个字节。例如一个采用二进制形式的地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“ . ”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做 “点分十进制法”,这显然比1和0容易记得多
  • IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128bit地址长度,每16个字节一组,分成8组十六进制数,这就解决了网络地址资源数量不够的问题

常用DOS命令

  • ipconfig:查看本机IP地址
  • ping IP地址:检查网络是否连通

示例:

 

特殊IP地址

  • 127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用
  • 190.168.0.0 – 192.168.255.255:私有地址,属于非注册地址,专门为组织机构内部使用

3.子网掩码

子网掩码的概念

子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。


子网掩码的作用

  • 子网掩码是一个32位地址,是与IP地址结合使用的一种技术。它的主要作用有两个,一是用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上。二是用于将一个大的IP网络划分为若干小的子网络。
  • 使用子网是为了减少IP的浪费。因为随着互联网的发展,越来越多的网络产生,有的网络多则几百台,有的只有区区几台,这样就浪费了很多IP地址,所以要划分子网。使用子网可以提高网络应用的效率。
  • 通过IP 地址的二进制与子网掩码的二进制进行与运算,确定某个设备的网络地址和主机号,也就是说通过子网掩码分辨一个网络的网络部分和主机部分。子网掩码一旦设置,网络地址和主机地址就固定了。子网一个最显著的特征就是具有子网掩码。与IP地址相同,子网掩码的长度也是32位,也可以使用十进制的形式。例如,为二进制形式的子网掩码:1111 1111.1111 1111.1111 1111.0000 0000,采用十进制的形式为:255.255.255.0。
  • 通过计算机的子网掩码判断两台计算机是否属于同一网段的方法是,将计算机十进制的IP地址和子网掩码转换为二进制的形式,然后进行二进制"与"(AND)计算(全1则得1,不全1则得0),如果得出的结果是相同的,那么这两台计算机就属于同一网段。
     

socket网络编程

Socket编程是在TCP/IP上的网络编程,Java的网络编程主要涉及到的内容是Socket编程。Socket,套接字,就是两台主机之间逻辑连接的端点。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地址、远程进程的协议端口。
Socket,实际上是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。

Socket整体流程

示例:下面是一个客户端和服务器端进行数据交互的简单例子,客户端输入正方形的边长,服务器端接收到后计算面积并返回给客户端,通过这个例子可以初步对Socket编程有个把握。

  • 服务器端
  • import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TestSockeServer {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(8080);
    
                while (true) {
                    System.out.println("服务器开始运行了,等待客户端连接上来");
                    Socket socket = serverSocket.accept();
                    System.out.println(socket.getInetAddress().getHostName());
                    System.out.println(socket.getLocalAddress());
                    System.out.println(socket.getLocalPort());
    
                    // 推送一条消息过去
                    String msg = "欢迎您进入我们的QQ";
                    OutputStream os = socket.getOutputStream();
                    PrintWriter out = new PrintWriter(os, true);
                    out.println(msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

  • 客户端

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
public class TestSocket {
    public static final String DES_IP = "127.0.0.1";
    public static final int DES_PORT = 8080;
    public static void main(String[] args) {
        Socket socket = new Socket();
        try {
            socket.connect(new InetSocketAddress(DES_IP, DES_PORT));
            System.out.println("成功连接到服务器");
            InputStream is = socket.getInputStream();
            String msg = null;
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            while ((msg = br.readLine()) != null ) {
                System.out.println("接受到服务器端传递过来的数据,数据是:"+ msg);
            }
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            out.println("我是一个客户端,我上来了,服务器,你好着吗?");
            out.println("第二条数据");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 效果:

服务器开始运行了,等待客户端连接上来
127.0.0.1
/127.0.0.1
8080
成功连接到服务器
接受到服务器端传递过来的数据,数据是:欢迎您进入我们的QQ

UDP网络编程

  • UDP编程和TCP编程相比,UDP编程就简单得多,因为UDP没有创建连接,数据包也是一次收发一个,所以没有流的概念。
  • 在Java中使用UDP编程,仍然需要使用Socket,因为应用程序在使用UDP时必须指定网络接口(IP)和端口号。
  • 注意:UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234。
  • 在服务器端,使用UDP也需要监听指定的端口。Java提供了DatagramSocket来实现这个功能。

tcp和udp的区别:

Tcp是面向连接的,udp是无连接的;
Tcp是可靠的,udp是不可靠的;
Tcp只支持点对点通信,udp支持一对一,一对多,多对多的通信模式;
Tcp是面向字节流的,udp是面向报文的;
Tcp有拥塞控制机制;udp没有拥塞控制,适合媒体通信;
Tcp首部开销(20个字节)比udp的首部开销(8个字节)要大;

代码示例:

服务器端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class TestUDPSever {
    public static final String DES_IP = "127.0.0.1";
    public static final int DES_PORT = 9999;

    public static void main(String[] args) {
        DatagramSocket socket = null;
        Scanner sc = null;
        try {
            socket = new DatagramSocket(8888);

            // 启动一个接收到线程,来进行数据接受
            UDPRreceiveMsg02 udpRreceiveMsg = new UDPRreceiveMsg02(socket);
            udpRreceiveMsg.start();

            sc = new Scanner(System.in);
            while (true) {
                System.out.print(">");
                String msg = sc.nextLine();
                byte[] buf = msg.getBytes();
                InetSocketAddress address = new InetSocketAddress(DES_IP, DES_PORT);
                DatagramPacket pd = new DatagramPacket(buf, 0, buf.length, address);
                socket.send(pd);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            socket.close();
        }

    }
}

class UDPRreceiveMsg02 extends Thread {
    private DatagramSocket socket;

    public UDPRreceiveMsg02(DatagramSocket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            receiveMsg();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void receiveMsg() throws IOException {
        while (true) {
            byte[] buf = new byte[1024];
            DatagramPacket pd = new DatagramPacket(buf, 0, buf.length);
            // 等待接受数据
            socket.receive(pd);
            // 将数据转换出来
            byte[] msg = pd.getData();
            String sendIP = pd.getAddress().getHostAddress();
            int sendPort = pd.getPort();
            System.out.println("接受到" + sendIP + ":" + sendPort + "发送过来的数据,数据是:" + new String(msg));
        }
    }
}

客户端
 

import java.io.IOException;
import java.net.*;
public class TestUDP {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        try {
            // 注意,创建一个udp socket对象,默认占据了8080
            datagramSocket = new DatagramSocket(8080);
            String msg = "你好啊,socket对象";
            byte[] bytes = msg.getBytes();
            // 数据报对象
            DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress("127.0.0.1", 8888));
            // 发送数据
            datagramSocket.send(packet);
            System.out.println("数据已经成功发送");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            datagramSocket.close();
        }
    }
}

效果显示:

 

 

TCP网络编程

特点:传输数据安全,可靠,面向连接的,点对点,长连接,效率相对较低

  • TCP/IP 模型。一组用于实现网络互连的通信协议,将协议分成四个层次。应用层、传输层、网络层、网络接口层。

  •   TCP,Transmission Control Protocol,传输控制协议。是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连接的过程需要三次握手,断开连接的过程需要四次挥手。

  •   UDP,User Datagram Protocol,用户数据报协议。是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小64KB。

  •   IP协议,Internet Protocol Address,互联网协议地址/网际协议地址。分配给互联网设备的数字标签(唯一标识)。IP地址分为两种。IPV4,分成4段8位的二进制数;IPV6,分成8段十六进制数。

  •   Port,端口号。在通信实体上进行网络通讯的程序的唯一标识。

InetAddress 类。

public class Test {
	public static void main(String[] args) throws UnknownHostException {
		// 获得本地主机地址对象
		System.out.println(InetAddress.getLocalHost());
		// 根据主机名称获得地址对象
		System.out.println(InetAddress.getByName("baidu.com"));
		// 获得所有相关地址对象
		InetAddress[] all = InetAddress.getAllByName("baidu.com");
		for (InetAddress inetAddress : all) {
			System.out.println(inetAddress);
		}
		for (InetAddress inetAddress : all) {
			System.out.println("获取IP地址字符串 " + inetAddress.getHostAddress());
			// 获得IP地址主机名
			System.out.println("获取IP地址主机名 " + inetAddress.getHostName());
		}
	}
}

结果:

KING-wjh/192.168.56.1
baidu.com/39.156.66.10
baidu.com/39.156.66.10
baidu.com/110.242.68.66
获取IP地址字符串 39.156.66.10
获取IP地址主机名 baidu.com
获取IP地址字符串 110.242.68.66
获取IP地址主机名 baidu.com

封装一个关闭流的通用方法。将 Closeable 接口作为泛型参数。

public class PublicMethod {
    public PublicMethod() {
    }
    public static void closeAll(Closeable... hh) {

        for (Closeable closeable : hh) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  TCP 编程实现客户端发送数据给服务器端。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
// 服务端
public class TestServer {
    public TestServer() {
    }
    public static void main(String[] args) throws IOException {
        ServerSocket ssocket = new ServerSocket(9527);
        // 与客户端建立连接
        Socket socket = ssocket.accept();
        System.out.println("等待客户端输入");
        InputStream ins = socket.getInputStream();
        byte[] bt = new byte[1024];
        // 接收客户端发来的数据
        int len = ins.read(bt); // 阻塞,接收到数据才往下走
        System.out.println(new String(bt, 0, len));
        OutputStream ous = socket.getOutputStream();
        // 向客户端发送数据
        ous.write("不在。".getBytes());
        PublicMethod.closeAll(ous, ins, socket, ssocket);
    }
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
// 客户端
public class TestClient {
    public TestClient() {
    }
    public static void main(String[] args) throws UnknownHostException, IOException {
        // 本地 ip 用来测试
        Socket socket = new Socket("127.0.0.1", 9527);
        System.out.println("客户端已连接");
        OutputStream os = socket.getOutputStream();
        // 向服务端发送数据
        os.write("在吗?".getBytes());
        InputStream ins = socket.getInputStream();
        byte[] bt = new byte[1024];
        // 接收服务端发来的数据
        int len = ins.read(bt); // 阻塞,接收到数据才往下走
        System.out.println(new String(bt, 0, len));
        PublicMethod.closeAll(ins, os, socket);
    }
}

效果显示:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南孚程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值