第五章 网络编程

第五章 网络编程

1.IP地址

每个设备都必须拥有一个独特的地址,用以标示其在网络上的位置

1.1 IP地址的组成

有32位,由4个8位二进制数组成,唯一标识网络上的每一台计算机

IP地址 = 网络地址 +主机地址

网络地址:标识计算机或网络设备所在的网段

主机地址:标识特定主机或网络设备

在这里插入图片描述

1.2 IP地址的配置和检测

查看IP地址,检测网络是否畅通:

  • 查看本机的IP地址:ipconfig
  • 测试网络是否通畅:ping 目标IP地址

1.3 DNS域名解析

Domain Name System,域名系统

从域名解析出IP地址

2.网络通信协议

为了在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合

协议
应用层HTTP、FTP、TFTP、SMTP、SNMP、DNS
传输层TCP、UDP
网络层ICMP、IGMP、IP、ARP、RARP
数据链路层由底层网络定义的协议
物理层由底层网络定义的协议

物理层: 基于电器特性的高低电压(电信号),高电压代表1,低电压代表0

数据链路层: 定义电信号的分组方式

网络层: 引入一套新的地址来区分不同的广播域

传输层: 端到端的连接通信

应用层(应用层,表示层,会话层): 规定了数据的传输格式

3.Socket

通信链路的端点就被称为“套接字”(英文名Socket)

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是提供给应用程序的接口

Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制

java.net包:

Socket

ServerSocket

DatagramPacket

DatagramSocket

InetAddress

3.1 基于TCP协议的Socket编程:

  • 基于TCP协议的Socket网络通信

    用来实现双向安全连接网络通信

  • Socket通信模型

    进行网络通信时,Socket需要借助数据流I/O来完成数据的传递工作

三次握手四次挥手 A(客户端)B(服务端)

三次握手(建立连接)

1.(A->B)携带syn数据包 A问B:你能收到我的消息吗?

2.(B->A)如果B同意连接则回复消息同意,向A发送syn+ack B回A:我收到了,你能收到我的消息吗?

3.(A->B)A再向B发送ack数据包 A回B:我收到了,开始通信

四次挥手(关闭连接)

1.(A->B)发送fin包 A:我要关闭,等你确认

2.(B->A)发送ack包,此时B会进入等待关闭状态 B:稍等,等待关闭

3.(B->A)发送fin包,进入最后确认状态 B:确认完成,可以关闭

4.(A->B)A收到后回复ack包,进入超时等待状态。等待结束关闭A,B收到ack后立即关闭连接 A确认关闭,B立即关闭

步骤:

建立连接->打开Socket关联的输入输出流->数据流中读写信息->关闭所有的数据流和Socket

在这里插入图片描述

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。

客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。

客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

客户端:

1.socket()函数

2.bind()函数可有可无,加上指定传输端口,不加随机分配端口;

3.connect()函数,填写服务端的地址与端口【网络间通信AF_STREAM】或者路径【进程间通信AF_DGRAM】

4.send()函数;

5.recv()函数。

服务端:

1.socket()函数;

2.bind()函数,必须加上指定传输端口【网络间通信AF_STREAM】或者是路径【进程间通信AF_DGRAM】 ;

3.listen()函数,使用isockfd;

4.accepc()函数,生成新的fd,inewfd;

5.send()函数,inewfd;

6.recv()函数,inewfd;

服务器端实现步骤:

  1. 建立连接,监听端口。
  2. 使用accept()方法等待客户端触发通信。
  3. 打开Socket关联的输入/输出流。
  4. 向输出流中写入信息。
  5. 从输入流中读取响应信息。
  6. 关闭所有的数据流和Socket。
package ch08.com.hz.sktest;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class Service {
    public static void main(String[] args) {
        Socket socket = null;
        InputStream is = null;
        OutputStream os = null;
        ServerSocket serverSocket = null;
        try {
            // 1.建立连接,监听端口。
            serverSocket = new ServerSocket(6001);
            System.out.println("服务器已启动...");
            // 2.使用accept()方法等待客户端触发通信。
            socket = serverSocket.accept();
            // 3.打开Socket关联的输入/输出流(需要先转换为字符流)
            is = socket.getInputStream();
            os = socket.getOutputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 4.向输出流中写入信息
            String str = br.readLine();
            System.out.println("我是服务器,客户端输入的消息为:" + str);
            // 对客户端输入信息进行处理
            String[] str2 = str.split("&");
            HashMap<String, String> hm = new HashMap<>();
            for (String str1 : str2) {
                String[] str3 = str1.split(":");
                hm.put(str3[0], str3[1]);
            }
            String reply = "登录失败";
            if ("admin".equals(hm.get("name"))
                    && "123456".equals(hm.get("password"))) {
                reply = "登录成功!";
            }
            // 5.从输入流中读取响应信息
            os.write(reply.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                // 6.关闭所有的数据流和Socket。
                os.close();
                is.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

客户端实现步骤:

  1. 建立连接,监听端口。
  2. 打开Socket关联的输入/输出流。
  3. 向输出流中写入信息。
  4. 从输入流中读取响应信息。
  5. 关闭所有的数据流和Socket。
package ch08.com.hz.sktest;

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

public class Client {
    public static void main(String[] args) {
        InputStream is = null;
        OutputStream os = null;
        Socket socket = null;
        BufferedReader bis = null;
        try {
            //1.建立连接,连接指向服务器及端口。
            socket = new Socket("127.0.0.1",6001);
            //2.打开Socket关联的输入/输出流。
            os = socket.getOutputStream();
            is = socket.getInputStream();
            //3.向输出流中写入信息。向服务器发送消息,需要先转换为字节流
            Scanner can = new Scanner(System.in);
            System.out.println("输入账号:");
            String name = can.next();
            System.out.println("输入密码:");
            String password = can.next();
            String str = "name:" + name + "&password:" + password;
            byte[] b = str.getBytes();
            os.write(b);
            socket.shutdownOutput();
            //4.从输入流中读取响应信息.从服务器读取信息。需要先把字节流转换为容易读取的字符流
            bis = new BufferedReader(new InputStreamReader(is));
            String str2 = bis.readLine();
            System.out.println("客户端输出:服务器回应为==>" + str2);
            socket.shutdownInput();
        }catch (UnknownHostException e) {
            e.printStackTrace();
        }  catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //5.关闭所有的数据流和Socket。
                bis.close();
                os.close();
                is.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

类型:

(1)流式套接字(SOCK_STREAM)

提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收(TCP协议)

(2)数据报式套接字(SOCK_DGRAM)(多线程、循环监听)

提供无连接服务,数据包以独立包形式发送,不提供无措保证,数据可能丢失,并且接收顺序混乱(UDP协议)

(3)原始套接字(SOCK_RAM)

Socket中实现对象的传递

对象要序列化

对象:
public class User implements Serializable {}

服务器:
ObjectInputStream ois = new ObjectInputStream(is);
User user = (User) ois.readObject();

客户端:
User user = new User(name, password);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(user);

多线程处理多请求(while循环)

一个专门负责监听的应用主服务程序

一个专门负责处理请求的线程程序

采用多线程的方式

3.2 基于UDP协议的Socket编程

TCPUDP
是否连接面向连接面向非连接
传输可靠性可靠不可靠
速度

创建DatagramSocket对象:

//创建一个数据包套接字,绑定到本机上任意一个可用的端口
DatagramSocket();
//创建一个绑定的数据报套接字, 与指定的datagramsocketimpl相关(一般不使用)
DatagramSocket(DatagramSocketImpl);
//通过制定的套接字地址来创建一个数据包套接字
DatagramSocket(SocketAddress);
//指定本地的一个端口,以此来创建数据包套接字
DatagramSocket(int);
//创建一个DatagramSocket对象,并绑定到指定的地址和端口上
DatagramSocket(int, InetAddress);

接收和发送数据:

//发送数据
public void send(DatagramPacket p) throws IOException  {.....}
//接收数据
 public synchronized void receive(DatagramPacket p) throws IOException {....}

相关方法:

// 返回绑定到本机套接字的端口
int getLocalPort();
//返回套接字的连接地址
InetAddress getInetAddress();
//关闭该数据报套接字
void close();

步骤

  1. 利用 DatagramPacket 对象封装数据包
  2. 利用 DatagramSocket 发送数据包
  3. 利用 DatagramSocket 接收数据包
  4. 利用 DatagramPacket 处理数据包
package ch08.com.hz.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

//客户
public class Client {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        DatagramPacket datagramPacket = null;
        try {
            InetSocketAddress isa = new InetSocketAddress("127.0.0.1",8888);
            datagramSocket = new DatagramSocket(7777);
            byte[] b = "客服你好".getBytes();
            //利用 DatagramPacket 对象封装数据包
            datagramPacket = new DatagramPacket(b,b.length,isa);
            //利用 DatagramSocket 发送数据包
            datagramSocket.send(datagramPacket);
            //利用 DatagramSocket 接收数据包
            System.out.println("接收客服回复...");
            datagramSocket.receive(datagramPacket);
            //利用 DatagramPacket 处理数据包
            byte[] bytes = datagramPacket.getData();
            int len = datagramPacket.getLength();
            System.out.println(new String(bytes,0,len));

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            datagramSocket.close();
        }
    }
}
package ch08.com.hz.udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

//客服
public class Server {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        DatagramPacket datagramPacket = null;
        try {
            System.out.println("客服在线...");
            //构建服务器+端口
            datagramSocket = new DatagramSocket(8888);
            //封装成包 DatagramPacket(byte[] buf,int lenth)
            byte[] bytes = new byte[1024];
            datagramPacket = new DatagramPacket(bytes, bytes.length);
            //接收客户端发来的数据
            datagramSocket.receive(datagramPacket);
            //获取接收到的数据
            byte[] b = datagramPacket.getData();
            //获取接收到的数据的长度
            int len = datagramPacket.getLength();
            //输出
            System.out.println(new String(b,0,len));

            System.out.println("客服回复中...");
            InetSocketAddress isa = new InetSocketAddress("127.0.0.1",7777);
            //回复客户
            String msg = "客户你好";
            //利用 DatagramPacket 对象封装数据包
            datagramPacket = new DatagramPacket(msg.getBytes(),msg.getBytes().length,isa);
            //利用 DatagramSocket 发送数据包
            datagramSocket.send(datagramPacket);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            datagramSocket.close();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值