【JAVA网络编程】

一.网络的基本认识
1、网卡
​ 每一个网卡都有一个被称为MAC地址的独一无二的48位串行号,它被写在卡上的一块内存中。在网络上的每一个计算机都必须拥有一个独一无二的MAC地址。

​ 没有任何两块被生产出来的网卡拥有同样的地址。这是因为电气电子工程师协会负责为网络接口控制器(网卡)销售商分配唯一的MAC地址
2、MAC地址、IP地址
其中物理地址指的就是MAC地址、IPv4 地址就是IP。

​ MAC地址也叫物理地址和局域网地址,主要用于确认网上设备的地址,类似于身份证号,具有唯一标识,每一个网卡制作完成之后就带有一个MAC地址,永远都不会改变。

​ IP地址,类似于你的现住址,是标记你在网络中的具体位置,一个网卡的IP地址是可以改变的。

IP地址的表示方式:32位
ip地址与子网掩码做与运算得到网络号
网络号
3.域名(就是ip的名字)你可以不知道你女朋友的电话号码,但是你一定得知道你女朋友的名字
DNS服务器
如果你的ip可以想象成电话号码的话,这个就是114
二.网络传输

网络的七层参考模型

应用层: 提供应用程序之间的通信。 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet
表示层 :处理数据格式,数据加密和压缩等。 没有协议
会话层 :建立、管理、终止两主机的会话。 没有协议
传输层 :建立主机的端到端连接。 TCP,UDP
网络层 :路径选择。 ICMP,RIP,OSPF,BGP,IGMP,IP
数据链路层: 负责两个相邻结点之间的数据传输。 SLIP,CSLIP,PPP,ARP,RARP,MTU
物理层 :使原始的数据比特流能在物理媒介上传输。 ISO2110,IEEE802,IEEE802.2
1、数据是怎么传输的
(1)TCP协议
建立连接
建立连接
断开连接
断开连接

(2)UDP协议
UDP(User Datagram Protocol,用户数据报协议)是一种传输层的协议,它提供不可靠服务,它是无连接的,所以不存在建立连接需要的时延(说人话就是直接怼,管你受得了受不了)

三.socket编程(tcp的实现,udp的实现)
通过域名,主机名,环回地址拿取ip

  @Test
  public void InetAddressTest() throws UnknownHostException {
        //从域名,回环都只能拿到一个ip地址 但是一个IP地址可以对应多个名字(主机名,域名,回环地址)
        System.out.println("InetAddress.getLoopbackAddress() = " + InetAddress.getLoopbackAddress());

        System.out.println("InetAddress.getByName(\"www.baidu.com\") = " + InetAddress.getByName("www.baidu.com"));
        //拿到的是环回地址
        System.out.println("InetAddress.getByName(\"localhost\") = " + InetAddress.getByName("localhost"));
        //拿到的是网卡
        System.out.println("InetAddress.getByName(\"吕超\") = " + InetAddress.getByName("吕超"));


    }

网络连接(可以通过url 打开连接,拿到流来抓取内容)

  @Test
    public void UrlTest() throws IOException {
        URL url = new URL("file:///D:\\IDEA激活\\a\\a.txt");
        System.out.println("url.getFile() = " + url.getFile());
        System.out.println("url.getPath() = " + url.getPath());
        System.out.println("url.getProtocol() = " + url.getProtocol());
        URLConnection urlConnection = url.openConnection();
        InputStream inputStream = urlConnection.getInputStream();
        FileOutputStream outputStream = new FileOutputStream("D:\\IDEA激活\\b\\a.txt");
        int len;
        byte[] bytes = new byte[1024 * 1024];
        while ((len = inputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
        }
    }

tcp

  /**
     * socket实现tcp(建立链接额三次握手,四次挥手)
     * @throws IOException
     */
    //服务端接受客户端发来的东西
    @Test
    public void tcpServerTest() throws IOException {
        //创建ServerSocket
        ServerSocket server = new ServerSocket();
        //绑定端口
        server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 8888));
        //监听端口
        Socket socket = server.accept();
        InputStream inputStream = socket.getInputStream();
        int len;
        byte[] bytes = new byte[1024 * 1024];
        while ((len = inputStream.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }
        inputStream.close();

    }



    @Test
    public void tcpClientTest() throws IOException {


        //创建Socket
        Socket socket = new Socket();
        //利用创建好的Socket进行连接
        socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 8888));
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("C哥牛逼666".getBytes(StandardCharsets.UTF_8));
        outputStream.close();
        socket.close();

    }

udp

   @Test
    public  void udpClientTest() throws IOException {
        //用户创建udp服务端口,也可以随机分配
        DatagramSocket socket = new DatagramSocket();
        //数据区
        String data="C哥牛逼666";
        byte[] bytes = data.getBytes();
        //构建数据包
        DatagramPacket datagramPacket = new DatagramPacket(
                bytes,0,bytes.length,
                InetAddress.getByName("localhost"),8080);
        socket.send(datagramPacket);
    }
    @Test
    public  void udpServerTest() throws IOException {
        //服务商创建udp接受端口,也可以随机分配
        DatagramSocket socket = new DatagramSocket(8080);
        byte[] buffer=new byte[1024];
        //构建数据包
        DatagramPacket datagramPacket = new DatagramPacket(
                buffer ,0,buffer.length
        );
        socket.receive(datagramPacket);
        String s = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
        System.out.println(s);
        socket.close();
    }

小案例
客户端

import Utils.MsgUtils;
import Utils.ScannerUtil;
import constant.Constant;
import constant.MessageType;
import message.Message;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Optional;

public class Client {
    public static void main(String[] args) throws IOException {
        //创建客户端接口
        Socket socket = new Socket();
        //拿到连接
        socket.connect(new InetSocketAddress(8080));
        OutputStream outputStream = socket.getOutputStream();
        InputStream inputStream = socket.getInputStream();
        System.out.println("请登录");
        //负责登陆的入口
        //表示当前登录的用户
        String username = null;
        while (true) {
            if (username == null) {
                username = login(outputStream, inputStream);
            } else {
                printOrder();
                String input = ScannerUtil.input();
                switch (Integer.parseInt(input)) {
                    case MessageType.To_Server:
                        sendToServer(username, outputStream, inputStream);
                        break;
                    case MessageType.To_Friend:
                        sendToFriend( username,outputStream);
                        break;
                    case MessageType.To_All:
                        sendToAll( username,outputStream, inputStream);
                        break;
                    case MessageType.RECEIVE:
                        receive(inputStream );
                        break;
                    default:
                        System.out.println("你选的不对,重新选");
                        break;
                }
            }
        }
    }

    private static void receive( InputStream inputStream) {
        while (true){
            Optional<Message> msg = MsgUtils.readMsg(inputStream);
            msg.ifPresent(m -> System.out.println(m.getUserName() + ":" + m.getContent()));
        }
    }

    private static void sendToServer(String username, OutputStream outputStream, InputStream inputStream) {
        //给服务器发消息
        System.out.println(username + ":");
        String msg = ScannerUtil.input();
        MsgUtils.writeMsg(outputStream, new Message(username, MessageType.To_Server, msg));
        //接受消息
        Optional<Message> message = MsgUtils.readMsg(inputStream);
        message.ifPresent(m -> System.out.println(username + ":" + message.get().getContent()));
    }

    private static void sendToFriend(String username,OutputStream outputStream ) {
        //给好友发消息
        System.out.println("请输入好友的名字:");
        String friend = ScannerUtil.input();
        boolean flag = true;
        while (flag) {
            System.out.println(username + ":");
            String msg = ScannerUtil.input();
            if ("bye".equals(msg)) {
                flag = false;
            }
            MsgUtils.writeMsg(outputStream, new Message(username, MessageType.To_Friend, msg, friend));

            //接受消息  在用户接受消息的时候会卡在这里 因为他要一直读(一个用户已经静进入接受状态,未发出,但是这个用户一直在读,所以会卡住)
//            Optional<Message> message = MsgUtils.readMsg(inputStream);
//            message.ifPresent(m -> System.out.println(username + ":" + message.get().getContent()));
        }
    }
    private static void sendToAll(String username,OutputStream outputStream, InputStream inputStream) {
        //给全体发消息
        boolean flag = true;
        while (flag) {
            System.out.println(username + ":");
            String msg = ScannerUtil.input();
            if ("bye".equals(msg)) {
                flag = false;
            }
            MsgUtils.writeMsg(outputStream, new Message(username, MessageType.To_Friend, msg));
        }
    }

    //打印的功能
    private static void printOrder() {
        System.out.println("请你选择功能" + "\n" +
                MessageType.To_Server + "、给服务器发消息" + " " +
                MessageType.To_Friend + "、给好友发消息" + " " +
                MessageType.To_All + "、群发"+
                MessageType.RECEIVE + "、接受信息");
    }

    //登陆的方法
    private static String login(OutputStream outputStream, InputStream inputStream) {
        //判断是否登录
        System.out.println("请你先输入用户名");
        String name = ScannerUtil.input();
        System.out.println("请你先输入密码");
        String pwd = ScannerUtil.input();
        Message message = new Message();
        message.setUserName(name);
        message.setType(MessageType.To_Login);
        message.setPassWord(pwd);
        //发送给服务器的消息
        MsgUtils.writeMsg(outputStream, message);
        //接受来自服务器的消息
        Optional<Message> msg = MsgUtils.readMsg(inputStream);
        if (msg.isPresent() && Constant.SUCCESS.equals(msg.get().getContent())) {
            return name;
        }
        return null;
    }

}


服务端

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

public class Server {
    public static void main(String[] args) {
        //创建服务器端口
        try( ServerSocket socket = new ServerSocket()) {
            //绑定端口
            socket.bind(new InetSocketAddress(8080));
            System.out.println("服务器已经启动" + "在" + socket.getLocalPort() + "端口");
            //监听端口
            //可建立多个链接,交给线程
            while (true) {
                Socket accept = socket.accept();
                new ServerThread(accept).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(服务端)多线程处理客户端的请求

import Utils.MsgUtils;
import constant.Constant;
import constant.MessageType;
import message.Message;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.Optional;

public class ServerThread extends Thread {

    private Socket accept;

    public ServerThread(Socket socket) {
        this.accept = socket;
    }

    @Override
    public void run() {
        try (InputStream inputStream = accept.getInputStream();
             OutputStream outputStream = accept.getOutputStream()) {
            while (true) {
                Optional<Message> message = MsgUtils.readMsg(inputStream);
                if (message.isPresent()) {
                    Message msg = message.get();
                    switch (msg.getType()) {
                        case MessageType.To_Login:
                            loginHandler(outputStream, inputStream, msg, accept);
                            break;
                        case MessageType.To_Server:
                            sendToClient(outputStream, inputStream, msg);
                            break;
                        case MessageType.To_Friend:
                            sendToTarget( msg);
                            break;
                        case MessageType.To_All:
                            sendToAll(msg);
                            break;
                    }
                }
            }
        } catch (
                IOException e) {
            e.printStackTrace();
        }


    }
    private  void sendToAll (Message message)  {
        //遍历所有的在线用户,拿到他们的socket
        for (Map.Entry<String,Socket> entry:Constant.Online_User.entrySet()) {
            try {
                MsgUtils.writeMsg(entry.getValue().getOutputStream(), message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private  void sendToTarget ( Message message)  {
   //先找到对应的socket
        Socket socket = Constant.Online_User.get(message.getFriendUserName());
        try {
            MsgUtils.writeMsg(socket.getOutputStream(),message);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private  void sendToClient (OutputStream outputStream, InputStream inputStream, Message message){
        //接受消息并打印
        System.out.println(message.getUserName() + "说:" + message.getContent());
// 已经读过消息了,就不要在读了,否则会阻塞在这里       Optional<Message> msg = MsgUtils.readMsg(inputStream);
        //发送消息
        MsgUtils.writeMsg(outputStream, new Message(Constant.SERVER_NAME, MessageType.Form_Server, Constant.OK));

    }

    private  void loginHandler (OutputStream outputStream, InputStream inputStream, Message message, Socket socket) {
        //判断是否已经登陆
        if (Constant.Online_User.containsKey(message.getUserName())){
            MsgUtils.writeMsg(outputStream, new Message(Constant.SERVER_NAME, MessageType.Form_Server, "已经登陆,不可重复登陆", Constant.DEFAULT_PWD));
        return;
        }
        //判断登录的逻辑
        if (!message.getPassWord().equals(Constant.DEFAULT_PWD) || message.getUserName() == null) {

            MsgUtils.writeMsg(outputStream, new Message(Constant.SERVER_NAME, MessageType.Form_Server, Constant.FAIL));
        } else {
            //登录成功,放在ConcurrentHashMap里面
            Constant.Online_User.put(message.getUserName(), socket);
            System.out.println(message.getUserName() + "登录成功");
            MsgUtils.writeMsg(outputStream, new Message(Constant.SERVER_NAME, MessageType.Form_Server, Constant.SUCCESS, Constant.DEFAULT_PWD));
        }
    }
}

读写工具包

package Utils;

import message.Message;

import java.io.*;
import java.util.Optional;

public class MsgUtils {
    //向输入流读消息
    public static Optional<Message> readMsg(InputStream inputStream) {
        ObjectInputStream ois;
        try {
            ois = new ObjectInputStream(inputStream);
            //封装成一个Optional防止空指针
            return Optional.ofNullable((Message) ois.readObject());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return Optional.empty();
    }

    //向输出流写消息
    public static void writeMsg(OutputStream outputStream, Message message) {
        ObjectOutputStream oos;
        try {
            oos = new ObjectOutputStream(outputStream);
            oos.writeObject(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


控制输入工具包

package Utils;

import java.util.Scanner;

public class ScannerUtil {
    private static final Scanner scanner = new Scanner(System.in);

    public static String input() {
        return scanner.next();
    }
}

实体类

package message;

import java.io.Serializable;

public class Message implements Serializable {
    private static final long serialVersionUID = 7857916520131819133L;
    private Integer type;
    private String content;
    private String UserName;
    private String PassWord;
    private String FriendUserName;


    public Message() {

    }

    //登录入口,用来登录的入口
    public Message(Integer type, String userName, String passWord) {
        this.type = type;
        UserName = userName;
        PassWord = passWord;
    }

    public Message(String userName, Integer type, String content) {
        this.type = type;
        this.content = content;
        UserName = userName;
    }

    public Message(String userName, Integer type, String content, String passWord) {
        this.type = type;
        this.content = content;
        UserName = userName;
        PassWord = passWord;
    }

    public Message(Integer type, String content, String userName, String passWord, String friendUserName) {
        this.type = type;
        this.content = content;
        UserName = userName;
        PassWord = passWord;
        FriendUserName = friendUserName;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getUserName() {
        return UserName;
    }

    public void setUserName(String userName) {
        UserName = userName;
    }

    public String getPassWord() {
        return PassWord;
    }

    public void setPassWord(String passWord) {
        PassWord = passWord;
    }

    public String getFriendUserName() {
        return FriendUserName;
    }

    public void setFriendUserName(String friendUserName) {
        FriendUserName = friendUserName;
    }

    @Override
    public String toString() {
        return "Message{" +
                "type=" + type +
                ", content='" + content + '\'' +
                ", UserName='" + UserName + '\'' +
                ", PassWord='" + PassWord + '\'' +
                ", FriendUserName='" + FriendUserName + '\'' +
                '}';
    }
}

常量池

package constant;

import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Constant {
    //成功的常量
    public static final String SUCCESS = "SUCCESS";

    //失败的常量
    public static final String FAIL = "FAIL";
    //服务器名字
    public static final String SERVER_NAME = "SERVER";

    //开始发送
    public static final String OK = "OK";
    //默认密码
    public static final String DEFAULT_PWD = "123";
    //用来装取用户名 与专属socket的集合
    public static final Map<String, Socket> Online_User = new ConcurrentHashMap<>(8);


}

用户状态常量

package constant;

public class MessageType {
    public static final int To_Server = 1;
    public static final int To_Friend = 2;
    public static final int To_All = 3;
    public static final int To_Login = 8;
    public static final int Form_Server = 5;

    public static final int RECEIVE =4 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长安归故里♬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值