Java - Network Programming

软件结构:
1.C/S结构:Client/Server结构
客户端和服务器结构    (如QQ、迅雷、百度网盘等软件)
2.B/S结构:Browser/Server机构
浏览器和服务器结构    (如谷歌、火狐、IE等浏览器)

两种结构各有优势,但都必须有网络的支持。
网络编程,就是在一定协议下,实现两台计算机的通信的程序。


网络编程三要素:
协议 IP地址 端口号
网络通信协议

1.UDP协议     用户数据报协议 
无连接,耗资小,通信效率高,但不能保证数据的完整性:网络直播,qq消息传输 
数据被限制在64kb内

2.TCP/IP协议  传输控制协议
面向连接,数据安全:迅雷下载、QQ文件传输、网页浏览
IP地址

互联网协议地址,用来给网络中的计算机设备做唯一的编号
可以将个人电脑=电话,那么IP地址=电话号码

IP地址分类:
IPv4:32位地址长度
IPv6:128位地址长度

常用命令:
ipconfig                查看本机IP地址
ping IP地址              检查网络是否连通

本机IP地址:        127.0.0.1、localhost
端口号

是一个逻辑端口,无法直接看到,可以使用一些软件查看端口号
当我们使用网络软件时,操作系统会为该软件分配一个随机的端口号(或该软件向OS申请一个指定的端口号)

网络通信的本质,是两个进程(应用程序)的通信
仅有IP地址,只能保证数据传输到对方计算机,不能保证传输到该计算机指定进程
使用IP地址+端口号,就可以保证数据准确传输到对方计算机的指定软件(进程/应用程序)上了

端口号由两个字节(即16位)组成,取值范围0-65535
注意:
1.  0-1024端口号不能使用,已被系统分配已知的网络软件
2.  网络软件的端口号不能重复

常用端口号:
1.网络端口         80                    www.baidu.com:80为正确网址(默认省略80)
2.数据库          mysql:3306  oracle:1521
3.Tomcat服务器    8080
TCP通信程序

1.客户端:java.net.Socket
创建Socket对象,向服务器发出连接请求,服务器端响应请求,两者建立连接开始通信
2.服务端:java.net.ServerSocket
创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接


通信步骤:
服务器端先启动,客户端发送请求,客户端与服务器端建立逻辑连接。
这个连接中包含一个IO对象,客户端与服务器端可以使用这个IO对象进行通信。
通信的数据不仅仅是字符,所以此IO对象是字节流对象。


注意:
1.服务器同时和多个客户端进行交互,服务器必须明确是和哪个客户端进行的交互
    在服务器端有accept方法,可以获取请求的客户端对象
2.服务器同时和多个客户端进行交互,需要使用多个IO对象
    服务器没有IO流,可以获取请求的客户端对象Socket,利用客户端Socket提供的IO流和客户端进行交互 
    即:服务器使用客户端的流和客户端进行交互
TCP通信的客户端
java.net.Socket     实现客户端套接字

套接字Socket:两台机器间通信的端点,包含了IP地址和端口的网络单位(Socket可以理解为插座)

构造方法:
Socket(String host,int port)    创建了一个流套接字并将其连接到指定主机的指定端口号
参数:
    String host:    服务器主机的名称/服务器的IP地址
    int port:       服务器的端口号

成员方法:
OutputStream getOutputStream()      返回此套接字的(字节)输出流
InputStream getInputStream()        返回此套接字的(字节)输入流
void close()                        关闭此套接字

实现步骤:
1.创建客户端对象Socket,构造方法绑定服务器的IP地址和端口号
2.使用Socket对象中的getOutputStream()获取网络字节输出流OutputStream对象
3.使用网络字节输出流OutputStream对象的write方法,给服务器发送数据
4.使用Socket对象中的getInputStream()获取网络字节输入流OutInStream对象
5.使用网络字节输入流InputStream对象的read方法,读取服务器回写的数据
6.释放资源(Socket)

注意:
1.客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
2.当我们创建客户端对象Socket时,就会去请求服务器和服务器经过3次握手建立连接通路
    若服务器未启动,会抛出异常
    若服务器已启动,就可以进行交互
TCP通信的服务器端
java.net.ServerSocket     实现服务器套接字

构造方法:
ServerSocket(int port)    创建绑定到特定端口的服务器套接字
服务器端必须明确是哪个客户端请求的服务器
故可以使用accept方法获取到请求的客户端对象

成员方法:
Socket accept()     侦听并接受到此套接字的连接

实现步骤:
1.创建服务器对象Socket,向系统要指定的端口号
2.使用ServerSocket对象中的accept方法,获取请求的客户端对象Socket
3.使用Socket对象中的getInputStream()获取网络字节输入流OutInStream对象
4.使用网络字节输入流InputStream对象的read方法,读取客户端发送的数据
5.使用Socket对象中的getOutputStream()获取网络字节输出流OutputStream对象
6.使用网络字节输出流OutputStream对象的write方法,给客户端回写数据
7.释放资源(Socket,ServerSocket)
注意:客户端上传文件时:

bis.read(bytes) 读取本地文件,读到结束标记后并不会把结束标记传输给服务器
故服务器接收此文件后,保存到服务器端时,因为没有结束标记,会陷入阻塞


解决方法:
客户端上传完文件后,给服务器添加一个结束标记

void shutdownOutput():
对于TCP套接字,任何以前写入的数据都将被发送,并且加上一个TCP的正常连接终止序列
//文件上传服务器:
//客户端:

public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 6666);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\考研\\沉迷学习.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        byte[] bytes = new byte[1024];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        socket.shutdownOutput();//注意:必须增添文件结束符
        System.out.println("客户端发送完毕");

        byte[] by = new byte[1024];
        InputStream is = socket.getInputStream();
        len = is.read(by);
        System.out.println(new String(by, 0, len));

        bis.close();
        socket.close();
    }
}
/*
服务器端:

数据源:客户端
目的地:11-Net\\1.jpg
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(6666);
        while (true) {
            Socket socket = serverSocket.accept();//若写入try中,会无限创建线程,导致死机
            /*
            多线程提高效率
            有一个客户端上传,就开启一个线程
             */
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {

                        String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt(99999) + ".jpg";
                        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("11_Net\\" + fileName));

                        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
                        System.out.println("服务器已收到");
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while ((len = bis.read(bytes)) != -1) {
                            bos.write(bytes, 0, len);
                        }

                        System.out.println("服务器保存完毕");
                        socket.getOutputStream().write("告诉客户端文件已收到".getBytes());

                        bos.close();
                        socket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
//        serverSocket.close()

    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325767817&siteId=291194637