黑马程序员技术交流社区

标题: 【石家庄校区】黑马七期day12笔记 [打印本页]

作者: Black_Y    时间: 2018-4-23 15:04
标题: 【石家庄校区】黑马七期day12笔记
本帖最后由 小石姐姐 于 2018-4-27 11:35 编辑

黑马七期day12笔记



网络编程


java php ui 前端与移动开发 c/c++ 网络营销 云计算 python
\


Socket (套接字)
用于描述IP地址和端口,是一个通信链的句柄.
Socket就是为网络编程提供的一种机制,通信的两端都有Socket;网络通信其实就是Socket间的通信;数据在两个Socket间通过IO传输.


网络通信三要素(协议 IP地址 端口号)
IP地址:InetAddress(点分十进制表示法)和(网络地址和主机地址)
IPv4和IPv6


公共地址和私有地址(局域网地址)
--网络中设备的表示,不易记忆,可用主机名


端口号
--用于标识进程的逻辑地址,不同进程的标识


传输协议
--通讯的规则\
--常见协议:TCP,UDP




UDP和TCP区别
UDP: USER DATAGRAM PROTOCOL, 用户数据报协议.
特点:
无连接的不可靠协议
数据传输大小限制为64K(一个包)
不需要建立连接即可传输
数据发送速度快, 发送方只发送数据, 不检查接收方是否真正接收到数据, 所以数据可能有丢包的情况
适用场景
适合实时性要求强的场合, 比如网络电话等环境, 这种协议延迟很小






端口号: 就是进程的地址
物理端口  网卡口


逻辑端口  我们指的就是逻辑端口


UDP协议


将数据源和目的封装成数据包中,不需要建立连接;
每个数据报的大小在限制在64K;因无连接,是不可靠协议;不需要建立连接,速度快


TCP协议(有一个管道,要进行连接)


建立连接,行小恒传输数据的通道;在连接中进行大数据量传输;通过三次握手完成
连接,是可靠协议;必须建立连接,效率会稍低


例如:A与B进行三次握手


InetAddress类:  此类表示互联网协议(IP)地址.




使用UDP协议发送数据 (DatagramSocket类:此类表示用来 发送 和 接收 数据,基于UDP协议的)
        创建Socket对象
        DatagramSocket ds=new DatagramSocket() ;
        创建数据并打包
        DatagramPacket:此类表示数据报包
        数据byte[]
        设备的地址IP
        进程的地址端口号
        发送数据
        释放资源


DatagramSocket():创建Socket对象并随机分配端口号


DatagramSocket(int port):创建Socket对象并指定端口号



使用UDP        协议接收数据
-创建接收端Socket对象
        //DatagramSocket();创建Socket对象并随即分配端口号
        //DatagramSocket(int port):创建Socket对象并指定端口
        DatagramSocket ds=new DatagramSocket() ;
-接收数据
-解析数据
-输出数据
-释放资源


java.net.Socket类: 基于TCP协议的Socket, 作为客户端
构造方法
Socket(InetAddress add, int port): 创建TCP客户端对象
成员方法
OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
InputStream getInputStream(): 获取输入流, 用于接收数据
void close(): 释放资源








TCP发送数据步骤
// 1. 创建客户端Socket对象(建立连接)
Socket socket = new Socket(InetAddress地址, 端口号);
// 2. 获取输出流对象
OutputStream outputStream = socket.getOutputStream();
// 3. 发送数据
outputStream.write(byte数组);
// 4. 释放资源
socket.close();




java.net.ServerSocket: TCP服务端
构造方法
ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口
成员方法
Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
void close(): 关闭Socket
TCP接收数据步骤
// 1. 创建服务端ServerSocket对象:
ServerSocket serverSocket = new ServerSocket(端口号);  // 指定要监听的端口号
// 2. 监听数据
Socket socket = serverSocket.accept();                // 该方法会阻塞, 直到有客户端连接
// 3. 获取输入流对象
InputStream inputStream = socket.getInputStream();
// 4. 获取数据
int dataLength = inputStream.read(装数据的byte[]数组);
String s = new String(byte[], 0, dataLength);
// 5. 输出数据
System.out.println(s);
// 6. 释放资源:
socket.close();
serverSocket.close();


TCP协议案例: 客户端发送, 服务端处理后返回客户端


public class TCPClient {


    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 10010);
        // 获取输出流对象
        OutputStream out = socket.getOutputStream();
        // 写出数据
        out.write("tcp, im coming!".getBytes());


        // 接收服务端返回的数据
        InputStream in = socket.getInputStream();
        // 一次读取一个字节数组
        byte[] bys = new byte[1024];
        int len;
        len = in.read(bys);
        // 转换为字符串
        String s = new String(bys, 0, len);


        System.out.println("客户端接收到服务端响应:"+s);


        // 释放资源
        socket.close();
    }
}


public class TCPServer {


    public static void main(String[] args) throws IOException {
        // 创建服务端ServerSocket
        ServerSocket serverSocket = new ServerSocket(10010);
        // 监听连接
        System.out.println("服务端启动...");
        Socket socket = serverSocket.accept();
        // 获取输入流对象
        InputStream in = socket.getInputStream();
        // 读取数据, 一次一个字节数组
        byte[] bys = new byte[1024];
        int len;
        len = in.read(bys);
        // 转为字符串
        String s = new String(bys, 0, len);
        System.out.println("服务端接收到数据:" + s);


        // 将字符串转为大写
        s = s.toUpperCase();


        // 获取输出流, 写回客户端
        OutputStream out = socket.getOutputStream();
        out.write(s.getBytes());


        // 释放资源
        socket.close();
    }
}












用户登录客户端
*/
public class LoginClient {


    public static void main(String[] args) throws IOException {
        // 创建客户端Socket
        Socket socket = new Socket("lishaoqing", 8888);


        // 获取键盘录入的用户名和密码
        BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名:");
        String username = inputBr.readLine();
        System.out.println("请输入密码:");
        String password = inputBr.readLine();


        // 写出数据
        PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);  // 自动刷新出去
        pw.println(username);
        pw.println(password);


        // 接收服务端返回的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        // 读取一行响应结果
        String result = br.readLine();
        System.out.println(result);


        // 释放资源
        socket.close();
    }
}


















模拟用户登录






/*
用户登录服务端
*/
public class LoginServer {


    public static void main(String[] args) throws IOException {
        // 创建服务端Socket
        ServerSocket serverSocket = new ServerSocket(8888);
        // 等待连接
        System.out.println("服务端启动...");
        Socket socket = serverSocket.accept();


        // 读取客户端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String username = br.readLine();
        String password = br.readLine();


        // 判断用户名和密码
        boolean canLogin = false;
        if ("itheima".equals(username) && "123".equals(password)) {
            canLogin = true;
        }


        // 返回响应结果
        PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
        if (canLogin) {
            pw.println("登录成功");
        } else {
            pw.println("登录失败");
        }


        // 释放资源
        socket.close();
    }
}


模拟用户登录案例改写
需求
改进用户信息的存储方式: 上例中只能存储一对用户名和密码. 但现实中会存储很多用户名和密码, 如何存储?
将用户名和密码封装进用户对象, 将多个对象封装到集合中. 用集合来模拟数据库(DB, database)
客户端不改
服务端在接收到客户端发送的用户名和密码后, 将用户名和密码封装到用户对象中, 然后获取集合, 判断该集合中是否有该用户对象(根据用户对象的属性判断), 如果有则登录成功, 没有则登录失败




public class User {


    private String username;
    private String password;


    public User() {
        super();
        // TODO Auto-generated constructor stub
    }


    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 boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (password == null) {
            if (other.password != null)
                return false;
        } else if (!password.equals(other.password))
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }


}


/*
模拟用户数据库
*/
public class UserDB {


    private static List<User> list = new ArrayList<>();


    static {
        list.add(new User("zhangsan", "123"));
        list.add(new User("lisi", "123"));
        list.add(new User("wangwu", "123"));
        list.add(new User("zhaoliu", "123"));
    }


    public static List<User> getUserList() {
        return list;
    }
}


/*
用户登录服务端
*/
public class LoginServer {


    public static void main(String[] args) throws IOException {
        // 创建服务端Socket
        ServerSocket serverSocket = new ServerSocket(8888);
        // 等待连接
        System.out.println("服务端启动...");
        Socket socket = serverSocket.accept();


        // 读取客户端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String username = br.readLine();
        String password = br.readLine();


        // 判断用户名和密码
        boolean canLogin = false;
        // 将用户名和密码封装为用户对象
        User user = new User(username, password);
        if (UserDB.getUserList().contains(user)) {
            canLogin = true;
        }


        // 返回响应结果
        PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
        if (canLogin) {
            pw.println("登录成功");
        } else {
            pw.println("登录失败");
        }


        // 释放资源
        socket.close();
    }
}


/*
用户登录客户端
*/
public class LoginClient {


    public static void main(String[] args) throws IOException {
        // 创建客户端Socket
        Socket socket = new Socket("lishaoqing", 8888);


        // 获取键盘录入的用户名和密码
        BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名:");
        String username = inputBr.readLine();
        System.out.println("请输入密码:");
        String password = inputBr.readLine();


        // 写出数据
        PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);  // 自动刷新出去
        pw.println(username);
        pw.println(password);


        // 接收服务端返回的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        // 读取一行响应结果
        String result = br.readLine();
        System.out.println(result);


        // 释放资源
        socket.close();
    }
}


















































































































欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2