网络编程(黑马程序员)

java.net.*

网络通信三要素

ip

Ipv4:32位//点分十进制
ipv6:128位

域名:通过域名在DNS服务器找IP
公网IP:192.168.0.0-192.168.255.255
本机IP:127.0.0.1

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

InetAddress类
表示IP地址

方法:
获取本机IP:getLocalHost()
根据IP地址或者域名返回InetAddress对象:getByName(String)
获取IP对应主机号:getHostName()
获取IP地址对象中的IP地址:getHostAddress()
指定毫秒内,判断主机与该IP对应的机器是否连接:isReachable()

端口号

标记在计算机设备上运行的应用程序
16位二进制,0-65535之间

分类:
周知端口:0-1023,知名应用占用
注册端口:1024-49151,用户进程或某些应用程序
动态端口:49152-65535,不分配给特定进程,动态分配

自己开发的程序用注册端口
不能有两个进程端口号一样

协议

规定的连接规则,以及数据传输标准

国际标准:
OSI

实际应用比较广的:
TCP/IP网络模型

应用层:
HTTP、FTP、SMTP

传输层:
UDP(用户数据报协议):
无连接、不可靠
自己IP、端口、目的IP、目的端口、数据
效率高
场景:
语音通话、视频直播

TCP(传输控制协议):
面向连接、可靠通信
保证数据可靠:
三次握手连接
传输数据进行确认
四次握手断开连接

全双工(双方收发)

网络层:
IP

数据链路层:
ARP

网络编程

UDP通信

java.net.DatagramSocket
客服端
服务端

创建:
创建客户端,随机分配端口号:DatagramSocket()
创建服务端,指定端口号:DatagramSocket(int port)

方法:
发数据包:send()
使用数据包接收数据:receive()

创建数据包:
DatagramPacket类
发出数据包:DatagramPacket(byte[],length,InetAdress,port)
接收数据包:DatagramPacket(byte[],length)

获取数据包实际收到的字节个数:getLength()

注意:用完要close关闭

多发多收

放在死循环中

TCP通信

java.net.Socket类

客服端:Socket(host,port)
获取字节输入流:getInputStream
获取字节输出流:getOutputStream

服务端:
ServerSocket(int port)

方法:accept()//等待获取客户端连接,返回Socket对象(客户端的)

注意:监听端口并不用于传输数据,而是负责监听连接请求。

多发多收

放死循环

服务端与多个客户端通信

多线程

TCP综合案例

聊天室:
简略实现:

client发消息

package com.chatwindow.www;

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

public class Client{
    public static void main(String[] args) throws Exception {
        Scanner sc=new Scanner(System.in);
        Socket socket=new Socket("127.0.0.1",8888);
        OutputStream ps=socket.getOutputStream();
        DataOutputStream ds=new DataOutputStream(ps);
        new Thread(new ClientRunnable(socket)).start();
        System.out.print("请输入用户名:");
        String msg=sc.nextLine();
        ds.writeUTF(msg);
        while(true){
            msg=sc.nextLine();
            if(msg.equals("exit")){
                System.out.println("欢迎下次光临!");
                ds.close();
                socket.close();
                break;
            }
            ds.writeUTF(msg);
        }
    }

}

client收消息(线程)

package com.chatwindow.www;

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

public class ClientRunnable implements Runnable{
    private Socket socket;
    public ClientRunnable(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        InputStream is= null;
        try {
            is = socket.getInputStream();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        DataInputStream di=new DataInputStream(is);
        while(true){
            try {
                String msg=di.readUTF();
                System.out.println(msg);
            } catch (IOException e) {
                System.out.println("再见");
                break;
            }

        }
    }
}

server接收请求

package com.chatwindow.www;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    public static List<Socket> list=new ArrayList<>();
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(8888);
        System.out.println("服务器已经启动!");
       while(true){
           Socket socket = ss.accept();
           list.add(socket);
           ServersRunnable sr = new ServersRunnable(socket);
           new Thread(sr).start();
       }
    }
}

server接发信息

package com.chatwindow.www;

import javax.xml.crypto.Data;
import java.io.*;
import java.net.Socket;

public class ServersRunnable implements Runnable{
    Socket socket;
    public ServersRunnable(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        InputStream is= null;
        try {
            is = socket.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        DataInputStream ds=new DataInputStream(is);
        String name="";
        try {
            name=ds.readUTF();
            for(Socket socket:Server.list){
                OutputStream os=socket.getOutputStream();
                DataOutputStream dos=new DataOutputStream(os);
                dos.writeUTF(name+":恭喜您登录成功!");
                dos.flush();
            }
            System.out.println(name+":恭喜您登录成功!");
        } catch (IOException e) {
            return ;
        }

        while(true){
            try {
                String msg=ds.readUTF();
                for(Socket socket:Server.list){
                    OutputStream os=socket.getOutputStream();
                    DataOutputStream dos=new DataOutputStream(os);
                    dos.writeUTF(name+":"+msg);
                    dos.flush();
                }
                System.out.println(msg);
            } catch (Exception e) {
                System.out.println(name+"用户下线了!");
                Server.list.remove(socket);
                try {
                    ds.close();
                    socket.close();
                } catch (Exception ex) {
                    System.out.println("服务器已关机");
                    break;
                }
                break;
            }
        }
    }
}

实现简单的BS架构

BS架构一定要满足HTTP协议
格式:
HTTP/1.1 200 OK
Content-Type:text/html;charst=UTF-8
空行
内容

package com.BS.www;

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

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket=new ServerSocket(8080);
        System.out.println("服务器启动成功");
        while(true){
            Socket socket=serverSocket.accept();
            new Thread(new Myserver(socket)).start();
        }
    }
}

package com.BS.www;

import jdk.net.Sockets;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

public class Myserver implements Runnable{
    private Socket socket;
    public Myserver(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        try (OutputStream os = socket.getOutputStream()) {
            PrintStream ps=new PrintStream(os);
            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type:text/html;charset=UTF-8");
            ps.println();
            ps.println("我爱你中国");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

每次新开线程好不好:
不好
高并发容易崩溃

解决:线程池

package com.BS.www;

import com.zsy.www.MyRunnable;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket=new ServerSocket(8080);
        System.out.println("服务器启动成功");
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(
                16*2,//IO设置为CPU数量二倍
                 16*2,
                60L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(20),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );
        while(true){
            Socket socket=serverSocket.accept();
            tpe.execute(new Myserver(socket));
        }
    }
}

你可能感兴趣的:(网络编程(黑马程序员))