java学习day20--网络编程

一.网络模型与协议:
OSI 七层模式 : 应用层,表示层,会话层,传输层,网络层,链路层,物理层
五层模型: 应用层, 传输层,网络层,链路层,物理层
四层模型 : 应用层, 传输层,网络层,链路层

应用层:http(超文本传输协议) ftp(文件传输协议) stmp (邮件发送协议) pop3(邮件接收协议), ssh ( 安全shell,用于远程登录)
传输层: tcp(安全可靠的协议) udp(不可靠)
网络层:ip

关于ip地址,作用是用来定位到网络上的另一台计算机
查询:     windows下可以使用 ipconfig来查看ip地址
          linux 下可以使用 ifconfig来查看ip地址

关于端口:作用是用来标记,要访问对方的哪个程序
常用的端口号:
mysql 3306
oracle 1521
sqlserver 1433
redis 6379
tomcat 8080
apache(http的服务) 80
ftp 21
ssh 22

二.传输层协议:
tcp协议:
TCP 协议的特点是: TCP 协议是一个有连接、可靠的协议。所谓有连接,指的是在进行 TCP通信之前,两个需要通信的主机之间要首先建立一条数据通道,就好像打电话进行交流之前,首先要让电话接通一样。所谓可靠,指的是 TCP 协议能够保证: 1、发送端发送的数据不会丢失; 2、接收端接受的数据包的顺序,会按照发送端发送的包的顺序接受。也就是说, TCP协议能够保证数据能够完整无误的传输。

udp协议:
与 TCP 协议相比, UDP 是一个无连接,不可靠的协议。 即:数据的发送方只负责将数据发送出去,数据的接受方只负责接受数据。发送方和接收方不会相互确认数据的传输是否成功。
相对于 TCP 而言, UDP 有一个优点:效率较高。因此,当我们在对数据传输的正确率
不太关心,但是对传输效率要求较高的情况下,可以采用 UDP 协议。典型的使用 UDP 协议的是网络语音以及视频聊天应用

三.java中的网络编程
Socket API 对tcp,udp协议做了封装,能够连接到对方主机,收发数据

tcp的例子:建立连接
服务器端

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

public class ServerTest {
    public static void main(String[] args) throws IOException {
        //传一个端口号与客户端进行连接,端口号一般使用4位以上的数字
        ServerSocket ss = new ServerSocket(12345);
        System.out.println("等待客户端连接");
        //等待客户端连接服务器方法,直到有客户端连接
        Socket socket = ss.accept();
        //将接收到的数据读入
        InputStream is = socket.getInputStream();
        byte[] by = new byte[1024];
        while(true) {
            int len = is.read(by);
            if(-1 == len) {
                break;
            }
            System.out.println(new String(by, 0, len));
        }
        //关闭
        socket.close();
    }
}

客户端

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class UserTest {
    public static void main(String[] args) throws IOException {
        //因为连接的是本机,所以将本机地址以及要连接的服务器端口号传入
        Socket socket = new Socket("localhost", 12345);
        Scanner sc = new Scanner(System.in);
        while(true) {
            String line = sc.nextLine();
            socket.getOutputStream().write(line.getBytes());
        }
    }
}

上述程序只是进行一个服务器和一个客户端进行一次性对话,接下来实现支持多个客户端连接的服务器
只需要将服务器端进行重写

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class ServerTest {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12345);
        //创建一个线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        System.out.println("等待客户端连接");
        while(true) {
            Socket socket = ss.accept();  //每连接一个新用户调用一次accept()
            //让线程池中的线程来处理
            threadPool.submit(() -> {
                try {
                    InputStream is = socket.getInputStream();  //读取接收的信息
                    InetAddress add = socket.getInetAddress();  //获取信息源的地址
                    byte[] by = new byte[1024];
                    while(true) {
                        int len = is.read(by);
                        if(-1 == len) {
                            break;
                        }
                        System.out.println(add + " " + new String(by, 0, len));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

上面的方式实现了多个客户端向服务端发送消息的功能,但是只有服务端自己能看到消息,所以要进行改进,让聊天室内所有的用户都能看到消息,即将服务器端接收的消息给所有客户端发送一份

扫描二维码关注公众号,回复: 3638284 查看本文章

服务器端

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class ServerTest {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12345);
        //创建一个线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        //创建一个集合用来存储所有的客户端socket
        ConcurrentHashMap<Socket, InetAddress> map = new ConcurrentHashMap<>();
        System.out.println("等待客户端连接");
        while(true) {
            //每接收一个新用户调用一次accept()
            Socket socket = ss.accept();
            InetAddress add = socket.getInetAddress();
            //将新用户添加到集合中
            map.put(socket, add);
            threadPool.submit(() -> {
               try {
                   InputStream is = socket.getInputStream();
                   byte[] by = new byte[1024];
                   while(true) {
                       int len = is.read(by);
                       if(-1 == len) {
                           break;
                       }
                       System.out.println(add + " " + new String(by, 0, len));
                        String content = add + " " + new String(by, 0, len);
                        //遍历map集合,将内容写到每个用户中
                       for(Socket userSocket : map.keySet()) {
                           OutputStream os = userSocket.getOutputStream();
                           os.write(content.getBytes());
                       }
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               }
            });
        }
    }
}

客户端
 

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;

public class UserTest {
    public static void main(String[] args) throws IOException {
        //因为连接的是本机,所以将本机地址以及要连接的服务器端口号传入
        Socket socket = new Socket("localhost", 12345);
        Scanner sc = new Scanner(System.in);

        //创建一个线程,读入发送过来的消息,并进行输出
        new Thread(() -> {
            try {
                InputStream is = socket.getInputStream();
                byte[] by = new byte[1024];
                while(true) {
                    int len = is.read(by);
                    if(-1 == len) {
                        break;
                    }
                    System.out.println(new String(by, 0, len));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();

        while(true) {
            String line = sc.nextLine();
            socket.getOutputStream().write(line.getBytes());
        }
    }
}


 

猜你喜欢

转载自blog.csdn.net/szy2333/article/details/81988118