Java基础知识网络编程

概述

java除了可以完成本地的操作,也可以完成网络通讯。比如想从自己的电脑上发送一个信息到张三的电脑上,张三收到信息之后再给我返回一个信息,利用java实现两个机器之间的数据的通讯。数据通讯的原理就是数据传输的过程,与本机的区别就是涉及到网络。

网络通讯要具备的要素和模型:

比如和张三通讯

1、首先要找到张三的主机,张三主机的标识就是IP地址(也就是主机的名字,IP地址由4个字节表示,可以表示很多主机,避免冲突)。

2、和张三通讯的方式有很多种,可以是QQ,也可以是微信。两个机器都要装有通讯的软件QQ或者微信。数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识,比如QQ用4000标识,微信用2900标识,为了方便称呼这个数字,叫做端口 ,这是逻辑端口,不是物理接口,也不是网线接口。

3、两个机器想要进行通讯,还要定义通信规则,使两方都能听懂对方的内容,这个通信规则就是协议。互联网的成千上万的机器都能进行通讯,因为国际组织定义了一个通用的协议TCP/IP,现在的操作系统里面都安装了这个协议 ,适用于广域网和局域网。

可以添加新的协议。也可以卸载TCP/IP协议,但是一般的机器卸载不了,因为已经固化到系统里面了。

但是某些特有的单位和组织,为了安全,他们的通讯方式和我们不一样,他们有自己特有的协议进行通讯,所以外界不能与之通讯,入侵不了。

IP地址介绍:

  • IP地址是由4段组成,每段是个字节,最大值是255
  • IP地址分成很多段,A/B/C等
  • 有个IP很特殊127.0.0.1,这是本地回环地址,当本机没有配地址时,本机默认的地址就是127.0.0.1,其中一个用处是用来测试网卡,ping 127.0.0.1 如果成功说明网卡正常。
  • 有些IP地址被保留不用于公网,用于局域网中。不同局域网中可以有相同的IP地址。192.168.. 是最常用的保留地址段,还有其他保留地址段。
  • 子网掩码的出现是为了解决电脑数量增多,IP地址不够用的问题。电信厂商们给某个区域只提供一个公网IP,通过子网掩码将这个区域内划分为局域网,整个区域走同一个公网IP。
  • 后来四段IP地址不够用了,便出现了六段IP地址,而且出现字母,数量多得多。

端口介绍

端口的大小:0-65535

其中0-1024端口被系统使用了,自己的程序也可以用,但是可能出现冲突现象。

几个默认端口:web服务:80、tomcat服务器:8080、MySql数据库:3306。可以自己定义端口。

网络模型

ISO网络模型中传输过程简单描述:

以QQ传送消息为例解释。

QQ软件在应用层上,首先将数据按照应用层的封装规则对数据进行封装。

然后传到表示层,再按照表示层的规则进行封装,然后进行会话层封装,传输层封装,网络层封装(加上IP地址),数据链路层封装,最后到达物理层,物理层就是网线、光纤、无线 等。这个过程叫做数据封包过程,根据每一层的协议加上每层的信息。数据封包之后,最后经过物理层传输到目的地址。

在目的地址会按照每层协议进行数据拆包,最终到达应用层,在应用层根据端口号确定将数据传给QQ软件。

TCP/IP模型

由于ISO的七层模型理解起来比较麻烦,后来出现了TCP/IP模型,将7层模型简化成了4层模型。将应用层、表示层、会话层归为应用层;将数据链路层和物理层归为主机至网络层,在加上传输层和网络层一共是4层。

我们进行Java网络编程就是在传输层和网际层,而Java Web开发,是在应用层,将底层的东西进行了封装。

传输层协议常见的有TCP、UDP

网际层最常见的协议IP

应用层的协议有很多比如HTTP和FTP等。

网络通讯要素

IP地址、端口号、传输协议。

Java语言进行网络通讯时,这三个要素是怎么体现的呢?

Java提供三个对象来操作三个要素。

IP地址:类 InetAddress 此类表示互联网协议 (IP) 地址。

IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。

没有构造函数。

获得对象的方式:static InetAddress getLocalHost() 返回本地主机

主要方法: String getHostAddress()

返回 IP 地址字符串(以文本表现形式)。

String getHostName()

获取此 IP 地址的主机名。

static InetAddress getByName(String host)

在给定主机名的情况下确定主机的 IP 地址。

端口号:用于标识进程的逻辑地址,不同进程的标识。有效端口号0~65535.其中0~1024系统使用或者保留端口。

传输协议:

两种传输协议比较常见:TCP和UDP,区别是什么?

UDP(面向无连接,发送数据之前双方不需要建立连接,类似邮局寄包裹):

- 将数据及源和目的封装成数据包中,不需要建立连接

- 每个数据包的大小限制在64K

- 因无连接,是不可靠协议

- 不需要建立连接,速度快

聊天通讯使用的就是UDP。网络视频也是UDP。对传输速度要求高,可靠性要求低的网络传输一般是UDP。

TCP(面向连接,双方必须都在(三次握手确定),相当于打电话):

- 建立连接,形成传输数据

- 在连接中进行大数据量传输 (不需要封装包)

- 通过三次握手完成连接,是可靠协议

- 必须建立连接,效率稍低 ,消耗资源

文件下载使用的就是TCP,可靠性要求高

Socket

Java网络编程指的就是Socket编程。Socket是插座(也称套接字)的意思。

Socket为网络服务提供一种机制。

两个主机如果想要通讯,需要有物理层的连接,比如网线,主机上都有一个网线的插口,连接两个主机。每个应用程序都有一个类似的插口,使两个主机上的同种应用程序之间可以网络通讯。这个插口就是Socket的概念。

所以,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket之间通过IO传输。

每种传输协议对应的建立Socket端点的方式,就有了UDP传输方式中Socket服务建立方式和TCP传输方式中Socket服务建立方式。

UDP传输方式

DatagramSocket类 此类表示用来发送和接收数据报包的套接字(插座)。

构造方法:

DatagramSocket()

构造数据报套接字并将其绑定到本地主机上任何可用的端口(随机)。

DatagramSocket(int port)

创建数据报套接字并将其绑定到本地主机上的指定端口(接收端和发送端都可以指定绑定的端口号)。

主要方法:

void receive(DatagramPacket p)

从此套接字接收数据报包。

void send(DatagramPacket p)

从此套接字发送数据报包。

void close()

关闭此数据报套接字。

DatagramPacket类 此类表示数据报包。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。

构造方法:

DatagramPacket(byte[] buf, int length)

构造 DatagramPacket,用来接收长度为 length 的数据包。

部分方法:

InetAddress getAddress()

返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。

byte[] getData()

返回数据缓冲区。

小实例:

需求:创建两个应用程序,一个用于发送数据,一个用于接收数据,接收数据的端口设为10000。

思路:

发送端

1,建立udpsocket服务

2. 提供数据,并将数据封装到数据包中

3. 通过socket服务的发送功能,将数据包发送出去

4.关闭资源

接收端:

1,建立udpsocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义数字标识, 方便于明确哪些数据过来,该应用程序可以处理。

2. 定义一个数据包,因为要存储接收到的字节数据,且数据包对象中有更多功能可以

提取字节数据中的不同数据信息

3. 通过socket服务的接收功能,将数据包存入已经定义好的数据包中。

4. 通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上

5. 关闭资源

import java.net.*;
class UdpSendDemo
{
    public static void main(String[] args) throws Exception
    {
        DatagramSocket ds=new DatagramSocket();

        byte[] data="udp is coming".getBytes();
        DatagramPacket dp=new DatagramPacket(data,data.length,InetAddress.getByName("127.0.0.1"),10000);
         ds.send (dp);
         ds.close();
    }
}
import java.net.*;
class UdpReceiveDemo
{
    public static void main(String[] args) throws Exception
    {
        DatagramSocket ds=new DatagramSocket(10000);
        byte[] data=new byte[1024];
        DatagramPacket dp=new DatagramPacket(data,data.length);
        ds.receive(dp);//阻塞式方法,没有接收到数据就等
        InetAddress ip=dp.getAddress();
        System.out.println("主机名"+ip.getHostName());
        System.out.println("IP"+ip.getHostAddress());
        System.out.println("数据:"+new String(dp.getData(),0,dp.getLength()));

    }
}

使用UDP方式编写简单的聊天程序

要求:

编写一个聊天程序。

有收数据的部分,和发数据的部分。

这两部分需要同时执行。

那就需要用到多线程技术。

一个线程控制收,一个线程控制发。

因为收和发动作是不一致的,所以要定义两个run方法。

而且这两个方法要封装到不同的类中。

发送类:

class SendThread implements Runnable
{
    private DatagramSocket ds=null;
    public  SendThread(DatagramSocket ds)
    {
        this.ds=ds;
    }

    public void run()
    {
        try
        {
            BufferedReader bur=new BufferedReader(new InputStreamReader(System.in));
            String line=null;
            while((line=bur.readLine())!=null)
            {
                byte[] senddata=line.getBytes();
                DatagramPacket dp=new DatagramPacket(senddata,senddata.length,InetAddress.getByName("192.168.1.114"),10001);
                ds.send(dp);
                //System.out.println("IP:"+InetAddress.getLocalHost().getHostName()+":"+line);
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("发送失败");
        }

    }
}

接收类:

class ReceiveThread implements Runnable
{
    private DatagramSocket ds=null;
    public  ReceiveThread(DatagramSocket ds)
    {
        this.ds=ds;
    }

    public void run()
    {
        try
        {
            while(true)
            {
                byte[] data=new byte[1024];
                DatagramPacket dp=new DatagramPacket(data,data.length);
                ds.receive(dp);//阻塞式方法,没有接收到数据就等
                InetAddress ip=dp.getAddress();
                String receiveData=new String(dp.getData(),0,dp.getLength());
                System.out.println("IP:"+ip.getHostAddress()+":"+receiveData);
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("接收失败");
        }

    }
}

聊天类:

{
    public static void main(String[] args) throws Exception
    {
        DatagramSocket sds=new DatagramSocket();
        DatagramSocket rds=new DatagramSocket(10002);

        new Thread(new SendThread(sds)).start();
        new Thread(new ReceiveThread(rds)).start();
    }
}

因为聊天是两个主机之间的通信,为了简单的测试程序,在同一主机上开启两个dos窗口测试。并且上面的代码只是通信的一方的代码,另外一方的代码没有差别,只是DatagramSocket和DatagramPacket绑定的端口不同:比如A的接收Socket服务对象的端口绑定为10002端口,发送的DatagramPacket绑定为对方的10001端口,而B的接收Socket服务对象的端口绑定为10001端口,发送的DatagramPacket绑定为对方的10002端口.两者的发送Socket服务不用绑定端口,让系统随机分配就好。听的好晕,看看代码就好了。简言之,发送数据时,用DatagramPacket确定接收者的端口,接收数据时,用DatagramSocket确定自身绑定的端口,这两个端口保持一致,就可以接收到数据啦。

TCP传输方式

UDP分的是发送端和接收端,而TCP分的是客户端和服务器端,分别对应两个对象:Socket和ServerSocket

客户端:

Socket类:此类实现客户端套接字(也可以就叫“套接字”)。

构造函数:

Socket(InetAddress address, int port)

创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

Socket(String host, int port)

创建一个流套接字并将其连接到指定主机上的指定端口号。

通过查阅Socket对象,发现在该对象建立时,就可以连接指定的主机。因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,并且连接成功。形成通路后,在该通道进行数据的传输。也有无参数的构造函数,此时用connect()方法确定目的端并连接。

Socket对象一旦建立成功,说明通信的通道已建立成功,便产生了Socket流也就是网络流。

Socket中封装了网络流,既有输入流也有输出流。可以用方法获得这两个流。

InputStream getInputStream()

返回此套接字的输入流。

OutputStream getOutputStream()

返回此套接字的输出流。 通过网络发送到对方主机上。

服务器端:

SocketServer类:此类实现服务器套接字。服务器套接字等待请求通过网络传入。

构造方法:

ServerSocket()

创建非绑定服务器套接字。

ServerSocket(int port)

创建绑定到特定端口的服务器套接字。

方法:

Socket accept()

侦听并接受到此套接字的连接。 这也是一个阻塞式方法。返回一个Socket对象。

多个客户端往服务端发送数据,服务端返回数据时,是如何做到那个客户端发来的,返回给哪个客户端,而不发生错误呢?

答:实际上,ServerSocket用accept()方法获得请求的客户端的Socket对象,利用该对象的输入流和输出流与该客户端通信,这样便不会发生发错对象的情况。而且,服务端的输入流和客户端的输出流对应,服务端的输出流和客户端的输入流对应。

TCP演示示例1:

客户端:

需求:给服务端发送一个文本数据

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

class TcpClient
{
    public static void main(String[] args) throws Exception
    {
        //创建客户端的socket服务,指定目的主机和端口,
        //一旦成功,通路建立,便有了Socket流即网络流,Socket流里面既有输入流也有输出流。
        Socket s=new Socket("192.168.1.114",10003);
        //为了发送数据,应该获取Socket流中的输出流
        OutputStream os=s.getOutputStream();
        os.write("tcp is coming".getBytes());

        s.close();
    }
}

服务端:

需求:定义端点接收数据并打印在控制台上。

服务端:

1,建立服务端的socket服务。ServerSocket();

并监听一个端口。

2,获取连接过来的客户端对象。

通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。

3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。

并打印在控制台。

4,关闭客户端(服务端有可能不关闭自己,但会关闭客户端,节省资源)

5、关闭服务端。(可选)

class  TcpServer
{
    public static void main(String[] args) throws Exception
    {
        //建立服务端socket服务。并监听一个端口。
        ServerSocket ss = new ServerSocket(10003);

        //通过accept方法获取连接过来的客户端对象。
        while(true)
        {
        Socket s = ss.accept();

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

        //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
        InputStream in = s.getInputStream();

        byte[] buf = new byte[1024];
        int len = in.read(buf);

        System.out.println(new String(buf,0,len));

        s.close();//关闭客户端.
        }
        //ss.close();
    }
}

TCP演示示例2:

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

思路:

程序基于示例1的程序进行简单修改即可。

客户端Socket对象的输出流写完数据之后,获得Socket的输入流,执行read()方法,这也是个阻塞式方法,若没读到数据,等待。

服务端读完数据之后,获得socket的输出流,写入反馈的内容即可。

class TcpClient2
{
    public static void main(String[] args)throws Exception
    {
        Socket s = new Socket("192.168.1.254",10004);

        OutputStream out = s.getOutputStream();

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

        InputStream in = s.getInputStream();

        byte[] buf = new byte[1024];

        int len = in.read(buf);

        System.out.println(new String(buf,0,len));

        s.close();
    }
}

class TcpServer2
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket ss = new ServerSocket(10004);

        Socket s = ss.accept();

        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+"....connected");
        InputStream in = s.getInputStream();

        byte[] buf = new byte[1024];

        int len = in.read(buf);

        System.out.println(new String(buf,0,len));

        OutputStream out = s.getOutputStream();

        Thread.sleep(10000);
        out.write("哥们收到,你也好".getBytes());

        s.close();

        ss.close();
    }
}

TCP练习

要求:

建立一个文本转换服务器。

客户端给服务端发送文本,服务断会将文本转成大写再返回给客户端。

而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。

分析:

客户端:

既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。

源:键盘录入。

目的:网络设备,网络输出流。

而且操作的是文本数据。可以选择字符流。

步骤

1,建立服务。

2,获取键盘录入。

3,将数据发给服务端。

4,获取服务端返回的大写数据。

5,结束,关资源。

都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。

服务端:

源:socket读取流。

目的:socket输出流。

都是文本,装饰。

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

class TranseClient
{
    public static void main(String[] args) throws Exception
    {
        Socket s=new Socket("192.168.1.6",10003);
        BufferedReader bur=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter buw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        BufferedReader burIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line=null;
        while((line=bur.readLine())!=null)
        {
            System.out.println("想要转换的文本为"+line);
            if(line.equals("over"))
                break;
            buw.write(line);
            buw.newLine();
            buw.flush();

            String str=burIn.readLine();
            System.out.println("转换后的文本为"+str);

        }
        bur.close();
        s.close();

    }
}

class TranseServer
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket ss=new ServerSocket(10003);
            Socket s=ss.accept();
            BufferedReader bur=new BufferedReader(new InputStreamReader(s.getInputStream()));
            BufferedWriter buw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            String line=null;
            while((line=bur.readLine())!=null)
            {
                System.out.println("要转换的文本为:"+line);
                if(line.equals("over"))
                    break;
                buw.write(line.toUpperCase());
                buw.newLine();
                buw.flush();
            }
            s.close();

           ss.close();

    }
}

这个练习容易出现的问题。

现象:客户端和服务端都在莫名的等待。

为什么呢?

因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等

而导致两端,都在等待。

readLine()方法读取一个文本行。通过下列字符之一即可认为某行已终止:换行 (‘\n’)、回车 (‘\r’) 或回车后直接跟着换行,如果没有遇到换行符,那么会一直等待。所以当源字节流是键盘录入时,要在程序中手动写入换行符,或者调用BufferedWriter的newLine()方法。

还有一个地方比较特殊,当客户端close(),相当于在输出流的末尾写入-1,服务端读取到-1,根据程序关闭或者不关闭。

时间: 2024-10-10 05:46:02

Java基础知识网络编程的相关文章

Java基础知识网络编程(TCP练习)

练习:复制文本 练习要求:把客户端的一个文件内容发到服务端,在服务端把数据存储到一个文件当中.相当于复制文件. import java.io.*; import java.net.*; class TxtCopyTestClient { public static void main(String[] args) throws Exception { Socket s=new Socket("192.168.1.6",10003); BufferedReader bur=new Buf

Java基础之网络编程

Java网络编程 课前思考1. 什么是TCP/IP协议?2. TCP/IP有哪两种传输协议,各有什么特点?3. 什么是URL?4. URL和IP地址有什么样的关系?5. 什么叫套接字(Socket)?6. 套接字(Socket)和TCP/IP协议的关系?7. URL和套接字(Socket)的关系?8.1 网络编程基本概念,TCP/IP协议简介 8.1.1 网络基础知识      网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中有两个主要的问题,一个是如何准确的定位网络

Java基础知识—网络Socket(六)

概述 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net 包中提供了两种常见的网络协议的支持: TCP:TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信.通常用于互联网协议,被称 TCP / IP. UDP:UDP 是用户数据报协议的缩写,一个无连接的协议.提供了应用程序之间要发送的数据的数据包. Socket编程 套接字使用TCP提供了两台计算机之间的通信机制. 客户端程序创建一个套接字,并尝试连接服务器的套接字.当连接建立时,服务器

黑马程序员-Java基础之网络编程

网络编程 实现计算机互联的三要素: 1.IP地址 本机回路IP:127.0.0.1 2.端口号(逻辑端口):用于标识应用程序. 端口号0~65535之间的整数:0~1024之间大部分已被用于一些知名的网络服务和应用,所以现在开发的网络应用程序端口号一般是1024以后的整数. 3.通信协议 TCP:三次握手机制,面向连接,稍慢.可靠 UDP:无连接,每个数据报大小限制在64K内.传输快.不可靠. 网络参考模型 TCP/IP参考模型 应用层:javaWeb开发 传输层:TCP/UDP 网际层:IP

java基础篇---网络编程(TCP程序设计)

TCP程序设计 在Java中使用Socket(即套接字)完成TCP程序的开发,使用此类可以方便的建立可靠地,双向的,持续的,点对点的通讯连接. 在Socket的程序开发中,服务器端使用serverSocket等待客户端的连接,对于Java的网络程序来讲,每一个客户端都使用一个socket对象表示. 在Java的网络程序中,客户端只要符合连接的通讯协议,那么服务端都可以进行接收. ServerSocket类主要用于服务器端程序的开发上,用于接收客户端的连接请求. Socket在服务器端每次运行时都

java基础篇---网络编程

一:IP与InetAddress 在Java中支持网络通讯程序的开发,主要提供了两种通讯协议:TCP协议,UDP协议 可靠地连接传输,使用三方握手的方式完成通讯 不可靠的连接传输,传输的时候接受方不一定可以接受的到 在Java中的所有网络程序的开发类都在java.net包中存在 IP地址简介 IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写.IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络

java基础教程-网络编程(七)

七.网络编程 7.1.IP协议 最重要的贡献是IP地址 7.2.TCP和UDP协议 TCP(快)可靠传输,发送时必须建立连接(三次握手协议 ) UDP(慢)不可靠传输,发送时无须建立连接 7.3.TCP 的TCP Server和TCP Client 注意,要首先启动Server,再启动Client 端口号是应用的入口,有两个字节,所以每个服务器最多能运行65536个应用程序,而TCP的端口和UDP的端口不一样,定义端口时,尽量定义1024以上的. 特别典型的端口号,http  80: //TCP

Java基础:网络编程总结

Java语言是在网络环境下诞生的,它是第一个完全融入网络的语言,虽然不能说它是对支持网络编程做得最好的语言,但是必须说是一种对于网络编程提供良好支持的语言.这归功于java的自身优势: 1.java语言与生俱来就是与平台无关的,有良好的跨平台性,所以运行在不同在平台上的java程序能够方便地进行网络通信. 2.java语言具有良好的安全机制,可以对程序进行权限检查,这对网络程序是至关重要的. 3.JDK中有丰富的网络类库,大大简化了网路变成的开发过程. 一.概念

Java基础7——网络编程

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程就是用来实现网络互联的不同计算机上运行的程序间可以进行数据交换 网络模型研究计算机网络之间以何种规则进行通信 网络模型一般是指OSI参考模型 TCP/IP参考模型 网络编程三要素 IP地址——网络中每台计算机的唯一标识 端口——计算机上每个应用程序的唯一标识 协议——通信之间的规则 计算机只能识别二进制的