Java基础-网络编程(二)

一、简述:

上一篇文章提到了网络编程的基础知识,今天将继续为大家介绍网络编程的基础知识,并提供相应的Demo。

二、TCP协议与UDP协议:

通过上一篇文章大家可以知道网络层主要协议是IP协议。而今天主要讲的是TCP和UDP协议以及简单的Demo。

TCP(Transfer Control Protocol)

一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport Layer)通信协议。

特点:

面向连接
点到点的通信
高可靠性
占用系统资源多、效率低

生活案例:

打电话

应用案例:

HTTP、FTP、TELNET、SMTP 等

UDP(User Datagram Protocol)

一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务

特点:

非面向连接,传输不可靠,可能丢失
发送方不管接收方是否准备好,是否收到也不确认
可以广播发送
非常简单的协议,开销小

生活案例:

电视与电视塔的关系

应用案例:

DNS、SNMP

三、常用的知识

InetAddress类:

封装计算机的IP地址,没有端口

//使用getLocalHost方法创建InetAddress对象
InetAddress addr = InetAddress.getLocalHost();
System.out.println(addr.getHostAddress());  //返回:192.168.1.110
System.out.println(addr.getHostName());  //输出计算机名

//根据域名得到InetAddress对象
addr = InetAddress.getByName(“www.163.com”); 
System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
System.out.println(addr.getHostName());  //输出:www.163.com

//根据ip得到InetAddress对象
addr = InetAddress.getByName(“61.135.253.15”); 
System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
System.out.println(addr.getHostName());  //输出ip而不是域名。如果这个IP地 址不存在或DNS服务器不允许进行IP地址和域名的映射,getHostName方法就直接返回这个IP地址。
InetSocketAddress:

包含端口,用于socket通信的

//包含端口
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress socketAddress2 = new InetSocketAddress(“localhost”,9000);
System.out.println(socketAddress.getHostName());
System.out.println(socketAddress2.getAddress());
URL

统一资源定位符,由4部分组成:* 协议、存放资源的主机域名、端口号和资源文件名 *

URL是指向互联网“资源”的指针

资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

URL u = new URL("http://www.baidu.con:80/index.html#aa?cansu=bjsxt");
System.out.println("获取与此url关联的协议的默认端口:"+u.getDefaultPort());
System.out.println(“getFile:”+u.getFile());  //端口号后面的内容
System.out.println("主机名:"+u.getHost());  //www.google.cn
System.out.println(“路径:”+u.getPath());  //端口号后,参数前的内容
System.out.println(“端口:”+u.getPort());  //存在返回80.否则返回-1
System.out.println("协议:"+u.getProtocol()); 
System.out.println("参数部分:"+u.getQuery()); 
System.out.println("锚点:"+u.getRef()); 
URL u = new URL("http://www.abc.com/aa/");
URL u2 = new URL(u,“2.html”);  //相对路径构建url对象
System.out.println(u2.toString());  //http://www.abc.com/aa/2.html

四、套接字Socket

我们开发的网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层如何使用传输层的服务呢?在应用层和传输层之间,则是使用套接字来进行分离。

图一

套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据;而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次的工作。

图二

Socket实际是网络传输层供给应用层的编程接口。传输层则在网络层的基础上提供进程到进程问的逻辑通道,而应用层的进程则利用传输层向另一台主机的某一进程通信。Socket就是应用层与传输层之间的桥梁。

图三

使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。

图四

五、TCP编程

需求:完成网络登录功能:
用户输入用户名密码,服务器给出登录成功或失败的提示
分析

  • 1 使用基于TCP协议的Socket网络编程实现
  • 2 TCP协议基于请求-响应模式
  • 3 在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序
  • 4 第一次通讯中等待连接的程序被称作服务器端(Server)程序
  • 5 利用IO流实现数据的传输

图五

TCP通信原理(详细步骤)

  • 1 服务器创建ServerSocket,在指定端口监听并并处理请求。
  • 2 客户端创建Socket,向服务器发送请求。

图六

网络登录功能分解:

  • 1 单向:客户端向服务器端发送字符串,服务器获取字符串并输出
  • 2 双向:服务器端给出客户端反馈,客户端得到反馈并输出
  • 3 对象:客户端向服务器端发送User对象,服务器端获取对象并输出
  • 4 多线程:服务器接收多个客户端的请求,并给出反馈每个客户请求开启一个线程

代码实例:
在这里我只给出功能分解的第四步的源码了,大家一个根据第四步,一步一步向前练习。

实体类:

import java.io.Serializable;

public class User implements Serializable{

    private static final long serialVersionUID = 1809727215200397637L;
    private String user;
    private String password;

    public User() {
        super();
    }

    public User(String user, String password) {
        super();
        this.user = user;
        this.password = password;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [user=" + user + ", password=" + password + "]";
    }

}

服务端代码:

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

public class TestServer {
    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建端口
        ServerSocket serversocket = new ServerSocket(8888);
        int i = 1;
        while (true) {
            // 使用serversocket进行监听
            Socket socket = serversocket.accept();
            new LoginThread(socket).start();

            System.out.print("第"+i+"个用户访问,IP地址是:" + socket.getInetAddress().getHostAddress());
            i++;
        }

        //socket.close();
    }
}

客户端代码:

import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import com.fddqq.socket.Entity.User;

public class TestClient {
    public static void main(String[] args) throws UnknownHostException, IOException {

        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        Scanner input = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String name = input.next();
        System.out.print("请输入密码:");
        String password = input.next();
        User user = new User(name, password);

        OutputStream os = socket.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(user);

        DataInputStream dis = new DataInputStream(socket.getInputStream());
        String result = dis.readUTF();
        System.out.println("客户端输出:" + result);
        input.close();
        dis.close();
        oos.close();
        socket.close();

    }
}

模拟数据库验证密码:

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;

import com.fddqq.socket.Entity.User;

public class LoginThread extends Thread {
    private Socket socket;

    public LoginThread() {
        super();
    }

    public LoginThread(Socket socket) {
        super();
        this.socket = socket;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        ObjectInputStream ois = null;
        DataOutputStream dos = null;
        try {
            InputStream is;
            is = socket.getInputStream();
            ois = new ObjectInputStream(is);

            User user = (User) ois.readObject();
            System.out.println(",服务器端输出:" + user);

            dos = new DataOutputStream(socket.getOutputStream());
            if ("fddqq".equals(user.getUser()) && "123456".equals(user.getPassword())) {
                String str = "登陆成功";
                dos.writeUTF(str);
            } else {
                String str = "登陆失败";
                dos.writeUTF(str);
            }

        } catch (IOException |

                ClassNotFoundException e) {
            e.printStackTrace();
        } finally {

            try {
                dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

运行结果
先启动服务器端代码,然后在启动客户端代码:

登陆失败:

客户端:

图七

服务器端:

图八

登陆成功:

客户端:
图九
服务器端:

图十

总结:
服务器创建ServerSocket,在指定端口监听并并处理请求;客户端创建Socket,向服务器发送请求
ServletSocket通过accept() 接收用户请求并返回对应的Socket,否则一种处于监听等待状态,线程也被阻塞

客户端发送数据需要输出流(写),客户端获取反馈数据需要输入流(读)
服务端反馈数据需要输出流(写),服务端获取请求数据需要输入流(读)
一旦使用ServerSocket和Socket建立了网络连接后,网络通信和普通IO流操作并没有太大区别

网络通信输出流建议使用DataOutputStream和ObjectOutputStream,与平台无关,输入流相应使用DataIntputStream和ObjectInputStream
如果是字符串通信也可以使用BufferedReader和PrintWriter,简单方便

六、UDP编程

需求:完成在线咨询功能:
客户和咨询师在线交流

分析
使用基于UDP协议的Socket网络编程实现
不需要利用IO流实现数据的传输
每个数据发送单元被统一封装成数据包的方式,发送方将数据包发送到网络中,数据包在网络中去寻找他的目的地。

UDP基本概念
DatagramSocket:用于发送或接收数据包
DatagramPacket:数据包

代码实例

客户端:

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

import com.fddqq.socket.Entity.User;

public class AskClient {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(8888); 
        int num = 9;
        double sum = 8.8;
        String str = "奋斗的蛐蛐!";
        User user = new User("奋斗的蛐蛐", "fddqq");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeInt(num);
        oos.writeDouble(sum);
        oos.writeUTF(str);
        oos.writeObject(user);

        byte [] buf = baos.toByteArray();

        DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 9999) ;
        ds.send(packet);

        ds.close();
    }
}

服务端:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class AskServer {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        DatagramSocket ds = new DatagramSocket(9999);
        byte [] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        ds.receive(packet);


        byte [] buf2 = packet.getData();
        InputStream bais = new ByteArrayInputStream(buf2, 0, packet.getLength());
        ObjectInputStream ois =new ObjectInputStream(bais);
        System.out.println(ois.readInt());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());
        System.out.println(ois.readObject());
//      System.out.println(new String(packet.getData(),0,packet.getLength()));      //获取数据
//      System.out.println(packet.getAddress());//获取对方IP
//      System.out.println(packet.getPort());   //获取对方端口
//      System.out.println(packet.getLength()); //获取数据长度

        ds.close();
    }
}

运行结果

先运行服务器端,在运行客户端,然后会在服务器端输出下面的场景:

图十一

七、结束语

今天就写到这里,说一千道一万,看的再多,不如自己手敲一遍。如果大家感觉有收获,不妨作作下面的习题,如果又需要下面习题的源码的可以留言给我,我会私信给大家源码连接地址。

喜欢的话可以点个喜欢与关注,感谢大家支持,也欢迎有不同意见的童鞋指教。谢谢大家!

使用基于UDP的Java Socket编程,完成在线咨询功能:

  • 1 客户向咨询人员咨询。
  • 2 咨询人员给出回答。
  • 3 客户和咨询人员可以一直沟通,直到客户发送bye给咨询人员。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值