Day25 网络编程(Socket编程)

计算机网络

计算机网络定义
  • 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

计算机网络定义分析
主干:计算机网络是计算机系统
网络功能:资源共享 信息传递
网络组成:
网络硬件:计算机 外部设备 通信线路 (连接)
网络软件:网络操作系统 网络管理软件 网络通信协议 (管理和协调)

计算机网络分类1(按照规模)

  • 局域网LAN
  • 城域网MAN
  • 广域网WAN

计算机网络分类2(传输介质)

  • 同轴电缆网络
  • 双绞线网络
  • 光纤网络
  • 卫星网络

计算机网络分类3(拓扑结构)

  • 星形网络
  • 总线网络
  • 环状网络
网络通信协议

网络通信协议

  • 计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准
  • 好比公路交通规则,学生守则

问题:网络协议太复杂

  • 计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?

解决方案:分层

  • 由于结点之间联系很复杂,在制定协议时,把复杂成份分解成
    一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。
网络通信协议的分层
  • 名义上标准:ISO/OSI参考模型
  • 事实上标准: TCP/IP协议栈(Internet使用的协议)
    这里写图片描述
    数据封装与拆封
    1、封装(发送数据)
    这里写图片描述
    2、拆封(接收数据)
    这里写图片描述
TCP/IP协议栈
  • 网络层主要协议IP协议
  • 传输层主要协议TCP和UDP
    这里写图片描述
TCP(transfer control protocol)
  • 一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议

特点:

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

生活案例:
打电话
应用案例:
HTTP FTP TELNET SMTP

这里写图片描述
三次握手
how are you ?
fine.And you?
Fine.

UDP(User DatagramProtocol )

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

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

    生活案例:
    发送短信 发电报

应用案例:
DNS SNMP

IP地址与端口

IP地址
用来标志网络中的一个通信实体的地址。通信实体可以是计算机,路由器等。

IP地址分类
IPV4:32位地址,以点分十进制表示,如192.168.0.1
IPV6:128位(16个字节)写成8个16位的无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984

特殊的IP地址
127.0.0.1 本机地址
192.168.0.0–192.168.255.255私有地址,属于非注册地址,专门为组织机构内部使用。

Java 中IP地址类的基本使用
InetAddress

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
/**
 * 认识IP地址类
 * @author Administrator
 *
 */
public class TestInetAddress {
    public static void main(String[] args) throws UnknownHostException {
        //获取本机的IP地址并显示
        InetAddress ia = InetAddress.getLocalHost();
        System.out.println(ia.toString());
        System.out.println(ia.getHostName());
        System.out.println(ia.getHostAddress());
        System.out.println(Arrays.toString(ia.getAddress()));

        //获取百度的IP地址并显示
        InetAddress ia2 = InetAddress.getByName("www.baidu.com");
        System.out.println(ia2.toString());
        System.out.println(ia2.getHostName());
        System.out.println(ia.getHostAddress());
        System.out.println(Arrays.toString(ia2.getAddress()));


    }
}

端口:port
IP地址用来标志一台计算机,但是一台计算机上可能提供多种应用程序,使用端口来区分这些应用程序。
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。
端口范围0—65535,16位整数
理解IP和端口的关系
IP地址好比每个人的地址(门牌号),端口好比是房间号。必须同时指定IP地址和端口号才能够正确的发送数据
IP地址好比为电话号码,而端口号就好比为分机号。
端口分类
公认端口 0—1023 比如80端口分配给WWW,21端口分配给FTP
注册端口 1024—49151 分配给用户进程或应用程序
动态/私有端口 49152–65535

认识InetSocketAddress
包含端口,用于socket通信的

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

/**
 * 认识InetSocketAddress = ip+port
 * @author Administrator
 *
 */
public class TestInetSocketAddress {

    public static void main(String[] args) throws UnknownHostException {
        //创建一个InetSocketAddress
        //InetSocketAddress  isa = new InetSocketAddress("www.baidu.com", 8888);

        InetAddress ia = InetAddress.getByName("www.baidu.com");
        InetSocketAddress  isa =  new InetSocketAddress(ia, 8888);
        System.out.println(isa.getHostName());
        System.out.println(isa.getAddress());
        System.out.println(isa.getPort());

        //

        //
    }
}

URL(Uniform Resource Locator)
统一资源定位符,由4部分组成:协议 、存放资源的主机域名、端口号和资源文件名。
URL是指向互联网“资源”的指针。
资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

import java.net.MalformedURLException;
import java.net.URL;
/**
 * 认识URL
 * IP    互联网地址   定位到一台计算机(或者路由器)  尚学堂
 * port  端口:定位到一台计算机上的一个应用程序(www服务、ftp服务、邮箱服务、数据库服务)  406教室
 * URL  统一资源定位器   定位到互联网上的任意资料(任意计算机任意服务的任意资源)  最终地址   XXX学校   XXX教室 几排几列学员姓名
 * 
 * @author Administrator
 *
 */
public class TestURL {

    public static void main(String[] args) throws MalformedURLException {
        //定义一个URL
        URL u = new URL("http://www.baidu.con:8080/207/ADFA/index.html#aaaa");

        System.out.println(u.getProtocol());//http
        System.out.println(u.getHost());
        System.out.println(u.getPort());
        System.out.println(u.getDefaultPort());
        System.out.println(u.getPath());
        System.out.println(u.getQuery());
        System.out.println(u.getRef());

    }
}

套接字Socket

我们开发的网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层如何使用传输层的服务呢?在应用层和传输层之间,则是使用套接字来进行分离。
套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据;而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次的工作。
这里写图片描述
这里写图片描述
Socket实际是网络传输层供给应用层的编程接口。传输层则在网络层的基础上提供进程到进程问的逻辑通道,而应用层的进程则利用传输层向另一台主机的某一进程通信。Socket就是应用层与传输层之间的桥梁
使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。
这里写图片描述
这里写图片描述
生活案例1:
如果你想写封邮件发给远方的朋友,如何写信、将信打包,属于应用层。信怎么写,怎么打包完全由我们做主;
而当我们将信投入邮筒时,邮筒的那个口就是套接字,在进入套接字之后,就是传输层、网络层等(邮局、公路交管或者航线等)其它层次的工作了。我们从来不会去关心信是如何从西安发往北京的,我们只知道写好了投入邮筒就OK了。
生活案例2:
如果你想发货给国外,你只要把货物放入集装箱,然后交给码头就可以了。发送什么货物,货物如何打包,完全有你做主。

码头就是套接字,剩下的事情就交给港口和货运公司处理就行了,具体细节我们无需了解

TCP编程

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
单向通信:

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

/**
 * 服务器端
 * 
 * 
 * 分解步骤1:单向通信  客户端----请求-->服务器端
 * 分解步骤2:双向通信  客户端<----响应--服务器端 
 * @author Administrator
 *
 */
public class LoginServer {

    public static void main(String[] args) throws IOException {
        //准备一个ServerSocket,进行监听和处理请求
        ServerSocket serverSocket = new ServerSocket(8888);

        //使用ServerSocket来监听
        Socket socket = serverSocket.accept();//如果请求没有到,代码在此阻塞

        //接收请求的数据
        InputStream is = socket.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String info = dis.readUTF();
        System.out.println("这里是服务器端,客户端发来的信息是:"+info);

        //关闭资源
        dis.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}




import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 客户端
 * @author Administrator
 *
 */
public class LoginClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        //准备一个Socket,用来发送或者接收数据
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        //使用Socket来发送一个请求给服务器端
        //OutputStream fos = new FileOutputStream("e:/readme.txt");
        OutputStream os = socket.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF("username=bjsxt&password=bjsxt");

        //关闭资源
        dos.close();
        os.close();
        socket.close();
    }
}

双向通信:

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

/**
 * 服务器端
 * 
 * 
 * 分解步骤1:单向通信  客户端----请求-->服务器端
 * 分解步骤2:双向通信  客户端<----响应--服务器端 
 * 分解步骤3:传输对象User
 * 分解步骤4:服务器端一直监听,对于每个监听到的请求会开启一个新线程来处理
 * 
 * 总结
 * 1.服务器创建ServerSocket,在指定端口监听并并处理请求;
 * 2.ServletSocket通过accept() 接收用户请求并返回对应的Socket,否则一种处于监听等待状态,线程也被阻塞
 * 3.客户端创建Socket,需要指定服务器的ip和端口号,向服务器发送和接收响应
 * 4.客户端发送数据需要输出流(写),客户端获取反馈数据需要输入流(读)
 * 5.服务端反馈数据需要输出流(写),服务端获取请求数据需要输入流(读)
 * 6.一旦使用ServerSocket和Socket建立了网络连接后,网络通信和普通IO流操作并没有太大区别
 * 7.网络通信输出流建议使用DataOutputStream和ObjectOutputStream,与平台无关,
 *          输入流相应使用DataIntputStream和ObjectInputStream
 * 8.如果是字符串通信也可以使用BufferedReader和PrintWriter,简单方便
 * 
 * 
 * @author Administrator
 *
 */
public class LoginServer {

    public static void main(String[] args) throws IOException {
        //准备一个ServerSocket,进行监听和处理请求
        ServerSocket serverSocket = new ServerSocket(8888);

        //使用ServerSocket来监听
        Socket socket = serverSocket.accept();//如果请求没有到,代码在此阻塞

        //接收请求的数据
        InputStream is = socket.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String info = dis.readUTF();
        System.out.println("这里是服务器端,客户端发来的信息是:"+info);


        //给客户端发送响应
        OutputStream os = socket.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF("登录成功,欢迎您");

        //关闭资源
        dis.close();
        dos.close();
        is.close();
        os.close();
        socket.close();
        serverSocket.close();
    }
}



import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 客户端
 * @author Administrator
 *
 */
public class LoginClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        //准备一个Socket,用来发送或者接收数据
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        //使用Socket来发送一个请求给服务器端
        //OutputStream fos = new FileOutputStream("e:/readme.txt");
        OutputStream os = socket.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF("username=bjsxt&password=bjsxt");


        //接收来自服务器的响应并输出结果
        InputStream is = socket.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String result = dis.readUTF();
        System.out.println("这里是客户端,服务器端的反馈结果:"+result);

        //关闭资源
        dos.close();
        os.close();
        socket.close();
    }
}

发送自定义对象,对象的序列化和反序列化

import java.io.Serializable;

/**
 * 用户类
 * @author Administrator
 *
 */
public class User implements Serializable{
    private String username;
    private String password;


    public User() {
        super();
    }
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }   
}

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
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.bjsxt.socket.entity.User;

/**
 * 客户端
 * @author Administrator
 *
 */
public class LoginClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        //准备一个Socket,用来发送或者接收数据
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        //使用Socket来发送一个请求给服务器端
        //OutputStream fos = new FileOutputStream("e:/readme.txt");
        OutputStream os = socket.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);


        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = input.nextLine();
        System.out.println("请输入密码");
        String password = input.nextLine();

        User user = new User(username, password);
        oos.writeObject(user);

        //接收来自服务器的响应并输出结果
        InputStream is = socket.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String result = dis.readUTF();
        System.out.println("这里是客户端,服务器端的反馈结果:"+result);

        //关闭资源
        oos.close();
        os.close();
        socket.close();
    }
}


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

import com.bjsxt.socket.entity.User;

/**
 * 服务器端
 * 
 * 
 * 分解步骤1:单向通信  客户端----请求-->服务器端
 * 分解步骤2:双向通信  客户端<----响应--服务器端 
 * 分解步骤3:传输对象User
 * 分解步骤4:服务器端一直监听,对于每个监听到的请求会开启一个新线程来处理
 * 
 * 总结
 * 1.服务器创建ServerSocket,在指定端口监听并并处理请求;
 * 2.ServletSocket通过accept() 接收用户请求并返回对应的Socket,否则一种处于监听等待状态,线程也被阻塞
 * 3.客户端创建Socket,需要指定服务器的ip和端口号,向服务器发送和接收响应
 * 4.客户端发送数据需要输出流(写),客户端获取反馈数据需要输入流(读)
 * 5.服务端反馈数据需要输出流(写),服务端获取请求数据需要输入流(读)
 * 6.一旦使用ServerSocket和Socket建立了网络连接后,网络通信和普通IO流操作并没有太大区别
 * 7.网络通信输出流建议使用DataOutputStream和ObjectOutputStream,与平台无关,
 *          输入流相应使用DataIntputStream和ObjectInputStream
 * 8.如果是字符串通信也可以使用BufferedReader和PrintWriter,简单方便
 * 
 * 
 * @author Administrator
 *
 */
public class LoginServer {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //准备一个ServerSocket,进行监听和处理请求
        ServerSocket serverSocket = new ServerSocket(8888);

        //使用ServerSocket来监听
        Socket socket = serverSocket.accept();//如果请求没有到,代码在此阻塞

        //接收请求的数据
        InputStream is = socket.getInputStream();
        ObjectInputStream ois = new ObjectInputStream(is);
        User user = (User)ois.readObject();
        System.out.println("这里是服务器端,客户端发来的信息是:"+user);


        //给客户端发送响应
        OutputStream os = socket.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        if("bjsxt".equals(user.getUsername())&& "bjsxt".equals(user.getPassword())){
            dos.writeUTF("登录成功,欢迎您");
        }else{
            dos.writeUTF("登录失败,请重新输入");
        }


        //关闭资源
        ois.close();
        dos.close();
        is.close();
        os.close();
        socket.close();
        serverSocket.close();
    }
}





使用多线程,实现服务器可以响应多个客户端的请求:

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

/**
 * 服务器端
 * 
 * 
 * 分解步骤1:单向通信  客户端----请求-->服务器端
 * 分解步骤2:双向通信  客户端<----响应--服务器端 
 * 分解步骤3:传输对象User
 * 分解步骤4:服务器端一直监听,对于每个监听到的请求会开启一个新线程来处理
 * 
 *  前台:接待+咨询
 *  前台:接待 每来一个咨询的学生,会分配一个咨询老师来处理   
 * 
 * 总结
 * 1.服务器创建ServerSocket,在指定端口监听并并处理请求;
 * 2.ServletSocket通过accept() 接收用户请求并返回对应的Socket,否则一种处于监听等待状态,线程也被阻塞
 * 3.客户端创建Socket,需要指定服务器的ip和端口号,向服务器发送和接收响应
 * 4.客户端发送数据需要输出流(写),客户端获取反馈数据需要输入流(读)
 * 5.服务端反馈数据需要输出流(写),服务端获取请求数据需要输入流(读)
 * 6.一旦使用ServerSocket和Socket建立了网络连接后,网络通信和普通IO流操作并没有太大区别
 * 7.网络通信输出流建议使用DataOutputStream和ObjectOutputStream,与平台无关,
 *          输入流相应使用DataIntputStream和ObjectInputStream
 * 8.如果是字符串通信也可以使用BufferedReader和PrintWriter,简单方便
 * 
 * 
 * 注意:对实体类的要求
 *  1.客户端和服务器端的User类必须在同一个包下,属性名也要相同,序列化版本号也要相同
 * 
 * @author Administrator
 *
 */
public class LoginServer {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //准备一个ServerSocket,进行监听和处理请求
        ServerSocket serverSocket = new ServerSocket(8888);

        //使用ServerSocket来监听
        int i=1;
        while(true){
            //监听用户的请求
            Socket socket = serverSocket.accept();//如果请求没有到,代码在此阻塞
            //开辟一个新的线程来处理该请求
            new LoginThread(socket).start();
            //输出当前请求的客户端的ip地址、端口号、是第几个用户
            InetAddress ia = socket.getInetAddress();           
            System.out.println("您是第"+(i++)+"个到访用户,您的IP地址是:"+ia.getHostAddress()
                    +",端口号是:"+socket.getPort());
        }

        //serverSocket.close();
    }
}


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

import com.bjsxt.socket.entity.User;

public class LoginThread extends Thread{

    private Socket socket;



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

    @Override
    public void run() {
        ObjectInputStream ois = null;
        DataOutputStream dos =  null;
        try{
            //接收请求的数据
            InputStream is = socket.getInputStream();
            ois = new ObjectInputStream(is);
            User user = (User)ois.readObject();
            System.out.println("这里是服务器端,客户端发来的信息是:"+user);


            //给客户端发送响应
            OutputStream os = socket.getOutputStream();
            dos = new DataOutputStream(os);
            if("bjsxt".equals(user.getUsername())&& "bjsxt".equals(user.getPassword())){
                dos.writeUTF("登录成功,欢迎您");
            }else{
                dos.writeUTF("登录失败,请重新输入");
            }
        }catch(IOException e){
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //关闭资源
            try {
                if(ois != null){
                    ois.close();
                }               
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(dos != null){
                    dos.close();
                }               
            } catch (IOException e) {
                e.printStackTrace();
            }
//          is.close();
//          os.close();
//          socket.close();
        }


    }
}

UDP编程

实现客服聊天功能
这里写图片描述
一次单向通信:

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

/**
 * 
 * 功能:在线客服
 * 技能:UDP编程
 * 
 * 注意
 * 1.TCP通信借助流来实现,UDP通信和流没有关系
 * 2.UDP中会将数据封装成特定的格式:数据包DatagramPacket(数据、IP地址、端口)
 * 3.UDP中服务器和客户端角色不是很明显,双方代码类似
 * 4.主动发起的客户端,被动接收的服务器端
 * 5.常用API
 *      DatagramSocket:发送和接收DatagramPacket
 *      DatagramPacket:封装数据的类
 * 
 * 
 * 问题分解
 * 1.一次单向通信
 * 2.一次双向通信
 * 3.多次双向通信
 * 4.传输对象而不是字符串
 * 
 * @author Administrator
 *
 */
public class AskServer {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(8888);//服务器端使用该端口接收数据
        //使用DatagramSocket来接收一个DatagramPacket
        byte [] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf, buf.length);
        socket.receive(dp);//将客户的数据放入dp

        //输出DatagramPacket的内容
        String str =  new String(dp.getData(),0,dp.getLength());
        System.out.println(str);
        System.out.println(dp.getLength());
        System.out.println(dp.getAddress());
        System.out.println(dp.getPort());

        //关闭DatagramSocket
        socket.close();
    }

}




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


public class AskClient {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(9999);//用来接收数据的端口

        //使用DatagramSocket来发送一个DatagramPacket
        String str = "亲,在吗";
        byte [] buf = str.getBytes();
        DatagramPacket dp = new DatagramPacket(buf, buf.length, 
                InetAddress.getLocalHost(), 8888);

         socket.send(dp);

        //关闭DatagramSocket
         socket.close();

    }

}

一次双向通信:

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

/**
 * 
 * 功能:在线客服
 * 技能:UDP编程
 * 
 * 注意
 * 1.TCP通信借助流来实现,UDP通信和流没有关系
 * 2.UDP中会将数据封装成特定的格式:数据包DatagramPacket(数据、IP地址、端口)
 * 3.UDP中服务器和客户端角色不是很明显,双方代码类似
 * 4.主动发起的客户端,被动接收的服务器端
 * 5.常用API
 *      DatagramSocket:发送和接收DatagramPacket
 *      DatagramPacket:封装数据的类
 * 
 * 
 * 问题分解
 * 1.一次单向通信
 * 2.一次双向通信
 * 3.多次双向通信
 * 4.传输对象而不是字符串
 * 
 * @author Administrator
 *
 */
public class AskServer {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(8888);//服务器端使用该端口接收数据
        //使用DatagramSocket来接收一个DatagramPacket
        byte [] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf, buf.length);
        socket.receive(dp);//将客户的数据放入dp

        //输出DatagramPacket的内容
        String str =  new String(dp.getData(),0,dp.getLength());
        System.out.println("客户端发来的信息:"+str);
//      System.out.println(dp.getLength());
//      System.out.println(dp.getAddress());
//      System.out.println(dp.getPort());

        //给出对方一个反馈信息
        String result = "亲,在的";
        byte [] buf2 = result.getBytes();
        DatagramPacket dp2 = new DatagramPacket(buf2, buf2.length, dp.getAddress(), dp.getPort());
        socket.send(dp2);
        //
        //关闭DatagramSocket
        socket.close();
    }

}




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


public class AskClient {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(9999);//用来接收数据的端口

        //使用DatagramSocket来发送一个DatagramPacket
        String str = "亲,在吗";
        byte [] buf = str.getBytes();
        DatagramPacket dp = new DatagramPacket(buf, buf.length, 
                InetAddress.getLocalHost(), 8888);

         socket.send(dp);

         //使用Socket接收反馈信息
         byte [] buf2 = new byte[1024];
         DatagramPacket dp2 = new DatagramPacket(buf2, buf2.length);
         socket.receive(dp2);

         System.out.println("服务器端的反馈:"+new String(dp2.getData(),0,dp2.getLength()));

        //关闭DatagramSocket
         socket.close();

    }

}

多次双向通信,聊天:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;

/**
 * 
 * 功能:在线客服
 * 技能:UDP编程
 * 
 * 注意
 * 1.TCP通信借助流来实现,UDP通信和流没有关系
 * 2.UDP中会将数据封装成特定的格式:数据包DatagramPacket(数据、IP地址、端口)
 * 3.UDP中服务器和客户端角色不是很明显,双方代码类似
 * 4.主动发起的客户端,被动接收的服务器端
 * 5.常用API
 *      DatagramSocket:发送和接收DatagramPacket
 *      DatagramPacket:封装数据的类
 * 
 * 
 * 问题分解
 * 1.一次单向通信
 * 2.一次双向通信
 * 3.多次双向通信
 * 4.传输对象而不是字符串
 * 
 * @author Administrator
 *
 */
public class AskServer {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(8888);//服务器端使用该端口接收数据
        Scanner input = new Scanner(System.in);
        while(true){
            //使用DatagramSocket来接收一个DatagramPacket
            byte [] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            socket.receive(dp);//将客户的数据放入dp


            //输出DatagramPacket的内容
            String str =  new String(dp.getData(),0,dp.getLength());

            if("bye".equals(str)){
                break;
            }
            System.out.println("客户端发来的信息:"+str);

            //给出对方一个反馈信息
            String result = input.nextLine();
            byte [] buf2 = result.getBytes();
            DatagramPacket dp2 = new DatagramPacket(buf2, buf2.length, dp.getAddress(), dp.getPort());
            socket.send(dp2);
        }


        //关闭DatagramSocket
        socket.close();
    }

}





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


public class AskClient {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(9999);//用来接收数据的端口
        Scanner input = new Scanner(System.in);
        while(true){
            //使用DatagramSocket来发送一个DatagramPacket
            String str = input.nextLine();//Android IOS Java
            byte [] buf = str.getBytes();
            DatagramPacket dp = new DatagramPacket(buf, buf.length, 
                    InetAddress.getLocalHost(), 8888);

             socket.send(dp);
             if("bye".equals(str)){
                 break;
             }
             //使用Socket接收反馈信息
             byte [] buf2 = new byte[1024];
             DatagramPacket dp2 = new DatagramPacket(buf2, buf2.length);
             socket.receive(dp2);

             System.out.println("服务器端的反馈:"+new String(dp2.getData(),0,dp2.getLength()));
        }


        //关闭DatagramSocket
         socket.close();

    }

}

传输系统对象和自定义对象:

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

import com.bjsxt.socket.entity.User;

/**
 * 
 * 功能:在线客服
 * 技能:UDP编程
 * 
 * 注意
 * 1.TCP通信借助流来实现,UDP通信和流没有关系
 * 2.UDP中会将数据封装成特定的格式:数据包DatagramPacket(数据、IP地址、端口)
 * 3.UDP中服务器和客户端角色不是很明显,双方代码类似
 * 4.主动发起的客户端,被动接收的服务器端
 * 5.常用API
 *      DatagramSocket:发送和接收DatagramPacket
 *      DatagramPacket:封装数据的类
 * 
 * 
 * 问题分解
 * 1.一次单向通信
 * 2.一次双向通信
 * 3.多次双向通信
 * 4.传输对象而不是字符串
 * 
 * @author Administrator
 *
 */
public class AskServer {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(8888);//服务器端使用该端口接收数据
        //使用DatagramSocket来接收一个DatagramPacket
        byte [] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf, buf.length);
        socket.receive(dp);//将客户的数据放入dp

        //输出DatagramPacket的内容
        byte [] buf2 = dp.getData();//1024
        ByteArrayInputStream bais = new ByteArrayInputStream(buf2, 0, dp.getLength());
        ObjectInputStream ois = new ObjectInputStream(bais);
        User user = (User)ois.readObject();
        System.out.println(user);
        //关闭DatagramSocket
        socket.close();
    }

}


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.bjsxt.socket.entity.User;


public class AskClient {

    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket,用之来发送和接收DatagramPacket
        DatagramSocket socket = new DatagramSocket(9999);//用来接收数据的端口

        //使用DatagramSocket来发送一个DatagramPacket
        User user = new User("bjsxt","bjsxt");

        ByteArrayOutputStream  baos = new ByteArrayOutputStream();
        ObjectOutputStream  oos = new ObjectOutputStream(baos);
        oos.writeObject(user);
        byte [] buf = baos.toByteArray();
        DatagramPacket dp = new DatagramPacket(buf, buf.length, 
                InetAddress.getLocalHost(), 8888);

         socket.send(dp);

        //关闭DatagramSocket
         socket.close();

    }

}

小结

网络的定义
网络的分类
网络协议:OSI模型和TCP/IP协议栈
IP、端口、URL、Socket定义
TCP编程实现网络登陆功能
UDP编程实现在线客服

小知识点:
1、字符串和字节数组的相互转化。
2、字节流都是用字节数组来传输的,byte[]。
3、TCP编程是Socket和流来实现的
而UDP是
DatagramSocket:发送和接收DatagramPacket
DatagramPacket:封装数据的类
4、UDP编程需要创建字节数字来接收数据。

编码题:
使用基于TCP的Java Socket编程,实现上传本地文件到服务器端。
提示:其实就是两次文件复制
第一次在客户端将文件从本地复制到网络socket
第二次再服务器端将文件从网络复制到本地
Client代码:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class UploadClient {

    public static void main(String[] args) throws IOException {
        //创建一个Socket,需要指定要访问的服务器和应用程序(IP和port)
        Socket socket = new Socket(InetAddress.getByName("192.168.2.188"), 8888);

        //使用Socket发送数据
        //创建输入流和输出流
        InputStream fis = new FileInputStream("d:/bjsxt.txt");
        OutputStream fos = socket.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);       ;
        InputStreamReader isr;
        //使用输入流和输出流完成复制操作(中转站是一个字节)
        int n;
        //读取一个字节
        n = bis.read();
        while(n!=-1){
            //写入另外一个文件
            bos.write(n);
            //再读一个字节
            n = bis.read();
        }
        //不可少,保证最后一次缓冲区数据的刷新
        bos.flush();
        //关闭输入流和输出流
        bis.close();//关闭底层流
        //bos.close();//1. flush  2.close 流   3.close socket
        socket.shutdownOutput();//not flush    close 流            not  close socket

        //接收服务器反馈信息
        InputStream is = socket.getInputStream();
        byte [] buf = new byte[1024];
        int len = is.read(buf);
        System.out.println(new String(buf,0,len));
        //关闭Socket
        socket.close();

    }

}

Server代码:

feredOutputStream(fos);
        //new BufferedReader(fis);
        InputStreamReader isr;
        //使用输入流和输出流完成复制操作(中转站是一个字节)
        int n;
        //读取一个字节
        n = bis.read();
        while(n!=-1){
            //写入另外一个文件
            bos.write(n);
            //再读一个字节
            n = bis.read();
        }
        //关闭输入流和输出流
        //bis.close();//关闭底层流
        bos.close();//先flush刷新缓冲,再关闭流

        //4.服务器给出响应信息
        OutputStream os = socket.getOutputStream();
        os.write("上传成功".getBytes());
        os.close();
        //关闭资源
        socket.close();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值