Java网络编程(一)

一、网络基础

一、TCP/IP协议

网络通信协议是计算机问进行通信所遵守的各种规则的集合。Internet的主要协议有:网络层的IP协议;传输层的TCP和UDP协议写;TCP协议是面向连接的,而UDP是面向不连接的,UDP传输速度更快,而TCP协议更安全;应用层的FTP、HTTP SMTP等协议。其中传输控制协议(Transpon Control Protocol, TCP)和网际互联协议(IntermetPoodIP是nemet的主要协议。它们定义了计算机与外设进行通信所使用的规则。

二、IP地址、域名和通信端口
  • IP地址用于唯一标识一个网络接口。IPv4采用32位地址,已经用完;IPv6 采用128位地址。
  • 域名表示一台网络中的电脑,由于IP地址不便于记忆,通常使用域名来访问特定的服务,域名解析服务器DNS负责将域名翻译成对应的IP地址,客户端再根据IP地址访问服务器:

    DNS
  • 通信端口唯一标识电脑上的一个进程(运行的程序)。端口号不是物理实体而是一个标记计算机逻相通有信道的正整数。端口号是用一个16位的-进制数来表示的,如果用十进制数来数来表示,,其范围为0~-65 535,其中,0~ 1023被系统保留。IP地址和端口号组成了所谓的TCP, UDP协议使用端口号将数的程序之间双向通信链路的最后终结点,是TCP和UDP的基础。Socket. Socker 是网络上运行的程序之间双向通信的链路的最终结点,是TCP和UDP的基础。
三、URL

URL是统一资源定位器Uniform Resource Locator
URL的基本结构由五部分组成,格式如下:

  传输协议: //主机名:端口号//文件名#引用
  • 传输协议 :TCP/IP协议
  • 主机名: 指资源所在的计算机。可以是IP地址,也可以是计算机的名称或域
  • 端口号:一个计算机中可能有多种服务,如Web服务,FTP服务或自己建立的服务>等。为了区分这些服务,就需要使用端口号,每一种服务用 一个端口号。
  • 文件名:文件名包括该文件的完整路径。在HTTP协议中,有一个默认的文件名是index. html,因此,下列两个地址是等价的。
    http://java.sun.com
    http://java.sun.com/index.html
  • 引用:引用就是资源内部的某个参考点。例如:http://java.sun.con/index.html#chapter1
四、Socket通信模式

Socket通常称为套接字,用于应用程序之间建立远程连接,Socket内部通过TCP/IP协议进行数据传输,可以简单的理解为对IP地址和端口号的描述。Socket编程需要实现服务器端和客户端,因为这两个设备通讯时,需要知道对方的IP和端口号。通常服务器端有个固定的端口号,客户端直接通过服务器的IP地址和端口号进行访问服务器端,同时告知客户端的端口号,于是他们之间就可以通过socket进行通信。

Socket通信模式

二、Socket编程

(1)客户端和服务器端实现通信

模拟客户端:首先创建一个用于模拟客户端socket,指明和哪个服务器通信和通信的端口,这里的IP地址是10.129.25.52,通信端口可以随便来一个8989,然后创建一个BuBufferedReader对象接收服务器发送的数据,然后再读取数据;给服务器发送数据,创建一个输出流PrintStream,输出数据。
模拟服务器端:先创建一个模拟服务器serverSocket,然后就要获得是哪个客户端连接到这个服务器,获取这个客户端的socket,其他的传输数据和客户端的传输过程一样。

//模拟客户端
class Client{
public static void main(String[] args) throws IOException {
    //1,创建用于通信的socket
    // 指明和谁通信:IP地址 端口号
    Socket socket = new Socket("10.129.25.52",8989);
    //接受服务器发来的数据
   BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    //读取服务器端发送的数据
    String line = null;
   while((line = br.readLine()) != null){
       System.out.println(line);
   }
   //向服务器端发送数据
    PrintStream printStream = new PrintStream(socket.getOutputStream());
    printStream.println("你好啊");
    socket.shutdownOutput();
  }
}

//模拟服务器端
class Server{
public static void main(String[] args) throws IOException {
    //1,创建服务器端的serverSocket
    ServerSocket serverSocket = new ServerSocket(8989);
    //2,获取连接的客户端的socket
    Socket clientSocket = serverSocket.accept();
    //3,向客户端发送数据
   PrintStream ps = new PrintStream(clientSocket.getOutputStream());
    ps.println("登陆成功");
    //告诉客户端输出完毕
    clientSocket.shutdownOutput();
    //4,接收客户端发来的数据
    BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    String line = null;
    while((line = br.readLine()) != null){
        System.out.println(line);
      }
  }
}
客户端输出

服务器端输出
(2)从终端输入数据,传送给客户端

这个和之前的区别就是,要先从终端读取数据,然后再传递给客户端

class MyClient{
public static void main(String[] args)  {
    //连接服务器端的socket
    Socket socket = null;
    try {
         socket = new Socket("10.129.36.120",8888);

         //接受服务器端数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line); //打印服务器端发送的数据
        }

    } catch (IOException e) {
        System.out.println("网络出错,请重新登陆");
    }finally {
        //关掉连接
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

      }

    }
}

class MyServer{
public static void main(String[] args) {
    //创建ServerSocket
    try( ServerSocket ss = new ServerSocket(8888)) {
       //监听客户端 获取哪个客户端访问
        Socket clientsocket = ss.accept();
        //从终端接受数据
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(clientsocket.getOutputStream());
        String line = null;
        while((line = keyin.readLine())!= null){
            //发送给客户端
            ps.println(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
      }
    }
}
服务器端输入

客户端输出结果
(3)客户端向服务器端上传一张图片

注:传输图片,视频,音频要用字节流

class Client{
public static void main(String[] args) throws IOException {
    //连接服务器 获取socket
    Socket socket = new Socket("127.0.0.1",8080);

    //创建服务器端对应的输入流 用于接收服务器端发来的数据
    BufferedReader br = new BufferedReader(new    InputStreamReader(socket.getInputStream()));
    System.out.println(br.readLine());

    //向服务器端发送文件(图片)
    //1.将文件写入到内存里
    String path = "/Users/pengxiaodong/Desktop/1.png";
    FileInputStream fis = new FileInputStream(path);

    //2.创建字节流 outputStream
    BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
    byte[] buf = new byte[1024];
    int len = -1;
    while ((len = fis.read(buf)) != -1){
        bos.write(buf,0,len);
    }
    socket.shutdownOutput();
  }

}

class Server{
public static void main(String[] args) throws IOException {
    //创建服务器端的ServerSoket
    ServerSocket ss = new ServerSocket(8080);

    //监听客户端连接
    //当有客户端来连接这个服务器 就可以得到对应的socket
    //当没有客户端来连接 服务器一直在这里等待
    Socket socket = ss.accept();

    //创建客户端对应的输出流 用于向这个客户端发送数据
    PrintStream ps = new PrintStream(socket.getOutputStream());
    ps.println("连接成功 可以发数据了!");
    BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
    String path = "/Users/pengxiaodong/Desktop/day1/java/src/main/java/day12/media/2.png";
    FileOutputStream fos = new FileOutputStream(path);

    byte[] buf = new byte[1024];
    int len = -1;
    while((len = bis.read(buf)) != -1){
        fos.write(buf,0,len);
     }
  }
}
(4)点对点聊天
  • 客户端:
    主线程:接受终端的输入,将终端的输入发送给服务器
    子线程:接收服务器发过来的数据
  • 服务器端:
    主线程:接收终端输入 将终端的输入发送给客户端
    子线程:接收客户端发过来的数据
class Client{
public static void main(String[] args) throws IOException {
    Socket socket = new Socket("10.129.25.52",8989);

    //用一个子线程处理服务器端的数据
    new Thread(new ClientThread(socket)).start();
    //主线程处理终端输入 发送给服务器端
    BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
    //创建一个发送给服务器的对象
    PrintStream printStream = new PrintStream(socket.getOutputStream());
    String line = null;
    while((line = keyin.readLine()) != null){
        printStream.println(line);
    }

    }
  }
/**
 * 创建一个客户端子线程
 */
class ClientThread implements Runnable{
private Socket socket;
//构造方法 告诉子线程在哪里读数据
public ClientThread(Socket socket){
    this.socket = socket;
}
//获取服务器端的输入流对象
BufferedReader bufferedReader = null;
@Override
public void run() {
    try {
        bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //读取数据
        String line = null;
        while((line = bufferedReader.readLine()) != null){
            System.out.println("服务器:"+line);
        }
    } catch (IOException e) {
        System.out.println("网络异常,请重新登陆");
        System.exit(-1);
    }finally {                 //出现异常,所有的资源都应该关闭 先关小的
        try {
            if(bufferedReader != null) {
                bufferedReader.close();
            }
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
      }
    }
}
class Server{
public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(8989);
    //获取客户端的socket
    Socket clientSocket = serverSocket.accept();

    //创建子线程
    new ServerThread(clientSocket).start();

    //终端的输入流对象
    BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
    //客户端的输出流
    PrintStream printStream = new PrintStream(clientSocket.getOutputStream());

    //读取终端的输入 将输入的内容输出给客户端
    String line = null;
    while((line = keyin.readLine()) != null){
        printStream.println(line);
    }

    }
}
/**
 * 创建一个子线程处理服务器端接收客户端的数据
 */
  class ServerThread extends Thread{
 private Socket socket;
 public ServerThread(Socket socket){
   this.socket = socket;
 }
BufferedReader bufferedReader = null;
@Override
public void run() {
    try {
         bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while((line = bufferedReader.readLine()) != null){
            System.out.println("客户端"+line);
        }
    } catch (IOException e) {
        System.out.println("网络异常,请重新登陆");
        System.exit(-1);
    }finally {
        try {
            if(bufferedReader != null) {
                bufferedReader.close();
            }
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    super.run();
  }
}
聊天结果展示

聊天结果展示
(6)实现群聊。
class Server{
//保存连接服务器的客户端
public static ArrayList sockets = new ArrayList();
public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(8384);
    //不停的等待客户端来连接
    while(true){
        Socket socket = serverSocket.accept();
        //当有客户端连接过来 就保存
        sockets.add(socket);

        //开启一个线程处理每个客户端的输入
        new ServerThread(socket).start();
      }
  }
}

/**
 * 创建一个子线程处理服务器端接收客户端的数据
 * 群发消息
 */
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
    this.socket = socket;
}
BufferedReader bufferedReader = null;
@Override
public void run() {
    try {
        bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while((line = bufferedReader.readLine()) != null){
            //群发消息
            //遍历数组
            for(Socket socket1:Server.sockets){
                //向每个对应的客户端发送消息
                PrintStream printStream = new PrintStream(socket1.getOutputStream());
                printStream.println(line);
            }
        }
    } catch (IOException e) {
        System.out.println("网络异常,请重新登陆");
        System.exit(-1);
    }finally {
        try {
            if(bufferedReader != null) {
                bufferedReader.close();
            }
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    super.run();
  }
}

class Client{
public static void main(String[] args) throws IOException {
    Socket socket = new Socket("10.129.25.52",8384);

    //用一个子线程处理服务器端的数据
    new Thread(new ClientThread(socket)).start();


    //主线程处理终端输入 发送给服务器端
    BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
    //创建一个发送给服务器的对象
    PrintStream printStream = new PrintStream(socket.getOutputStream());
    String line = null;
    while((line = keyin.readLine()) != null){
        printStream.println(line);
    }

    }
}
class ClientThread implements Runnable{
private Socket socket;
//构造方法 告诉子线程在哪里读数据
public ClientThread(Socket socket){
    this.socket = socket;
}
//获取服务器端的输入流对象
BufferedReader bufferedReader = null;
@Override
public void run() {
    try {
        bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //读取数据
        String line = null;
        while((line = bufferedReader.readLine()) != null){
            System.out.println(line);
        }
    } catch (IOException e) {
        System.out.println("网络异常,请重新登陆");
        System.exit(-1);
    }finally {                 //出现异常,所有的资源都应该关闭 先关小的
        try {
            if(bufferedReader != null) {
                bufferedReader.close();
            }
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
      }
    }
 }