网络编程(Socket)——InetAddress类、UDP传输、TCP传输

C/S结构:全称为Client/Server结构,是指客户端和服务器结构

开发成本高,维护周期长,需要开发客户端和服务器

B/S结构:全称为Browser/Server结构,是指浏览器和服务器结构

开发成本较低,维护周期短,只要开发一个服务器即可

 

网络三要素:    通过IP找主机,通过端口号找程序,通过协议确定如何传输

IP地址:网络设备的唯一表示,通过IP地址可以找到对应的设备

端口:进程的唯一表示,每一个程序都有端口号(一个十进制的整数,取值范围(0~65535))

0~1024以下的端口是系统保留使用的,程序员开发得用1024~65535端口号

协议:用来规定计算机与计算机之间数据传输的格式(例:UDP协议和TCP协议)

 

 

InetAddress类:

一个InteAddress就代表一个IP地址对象          (127.0.0.1表示本机地址)

构造方法:

static  InetAddress  getLocalHost()                                                       获得本机IP地址对象

InetAddress ia = InetAddress.getLocalHost();

static  InetAddress  getByName(String host)                                      根据主机名或IP地址字符串获得InetAddress对象

InetAddress ia = InetAddress.getByName("192.168.12.41");

 

常用方法:

String  getHostName()                                                                          获得InetAddress对象的主机名

InetAddress ia = InetAddress.getLocalHost();
System.out.println(ia.getHostName());                //输出:cikinn-PC

String  getHostAddress()                                                                      获得InetAddress对象的IP地址字符串

InetAddress ia = InetAddress.getLocalHost();
System.out.println(ia.getHostAddress());            //输出:172.20.10.2

 

 

UDP协议:

特点:

面向无连接协议(无需连接就将信息发出,不管对方是否收到)

只管发送,不确认对方是否收到

速度快,但不可靠,会造成数据丢失

传输数据大小限制在64K以下

基于数据包传输:将要发送的数据,接收端的IP地址、

端口号等信息打包到一个数据包发送

 

DatagramSocket类:

构造方法:

DatagramSocket()                                                                                  创建发送端的Socket对象

DatagramSocket ds = new DatagramSocket();

DatagramSocket(int port)                                                                      创建指定端口号的接收端Socket对象

DatagramSocket ds = new DatagramSocket(8989);

创建时传入端口号的则为接收端Socket,没有端口号的是发送端Socket对象

 

常用方法:

void  send  ()            发送数据包

void  recive  ()          接受数据包

void  close  ()           关闭Socket对象

 

 

DatagramPacket类:  

数据包对象,用来封装要发送或接受的数据的包对象

构造方法:

DatagramPacket(byte[] buf, int length, InetAddress address, int port)                               用于创建发送端数据包对象

InetAddress ia = InetAddress.getLocalHost();
byte [] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,b.length,ia,8989);

buf 要发送的内容 ;length 要发送的内容长度,单位字节; address 接收端的ip地址 ;port 接收端口号


DatagramPacket(byte buf[], int length)                                                                                       用于创建接收端数据包对象

byte [] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,b.length);

buf 用于接收数据的数组; length buf数组的长度

创建对象时4个参数的是发送端对象,2个参数的是接受端对象

 

UDP传输的流程逻辑如图

首先由DatagramSocket发送端将DatagramPacket数据包发送出去

接受端接受的时候也得由一个DatagramPacket接受发送过来的数据包,然后再到服务器接受

 

UDP服务器:

DatagramSocket ds = new DatagramSocket(8989);            //服务器的DatagramSocket端口号
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,b.length);
ds.receive(dp);
System.out.println(dp.getAddress()+" "+new String(b,0,dp.getLength()));

UDP客户端:

DatagramSocket ds = new DatagramSocket();
InetAddress ia = InetAddress.getLocalHost();
byte[] b = "申请连接UDP服务器".getBytes();
DatagramPacket dp = new DatagramPacket(b,b.length,ia,8989);
ds.send(dp);
ds.close();

使用DatagramSocket的send()和recive()方法对datagramPacket数据包对象进行发送和接受

客户端的DatagramPacket对象必须传入服务器的IP地址对象(ia)和服务器的端口号(8989)一致

最后客户端发送完信息后记得调用close()方法关闭发送端对象

 

先开启服务器,然后开启客户端,即可在服务器中接收到客户端发送的申请连接消息

 

 

TCP协议:

面向连接的协议

通过三次握手建立连接,形成数据传输通道

通过四次挥手断开连接

速度慢,但可靠,传输数据大小没有限制

基于IO流的数据传输

 

Socket类:

一个该类对象就代表一个客户端程序

构造方法:

Socket  (String  host , int  port )                                                         根据服务器的IP地址和端口号创建客户端对象

Socket s = new Socket("127.0.0.1", 8989);

Socket  (InetAddress adrss , int  port )                                           根据服务器的IP地址对象和端口号创建客户端对象

Socket s = new Socket(InetAddress.getLocalHost(),8989);

以上两种方式都代表创建本机IP地址端口号8989的客户端对象

 

常用方法:

OutputStream  getOutputStream  ()                                                    获得字节输出流对象

Socket s = new Socket(InetAddress.getLocalHost(),8989);
OutputStream out = s.getOutputStream();

InputStream  getInputStream  ()                                                           获得字节输入流对象

Socket s = new Socket(InetAddress.getLocalHost(),8989);
InputStream in = s.getInputStream();

 

 

ServerSocket类:

一个该类对象就代表一个服务器端程序

ServerSocket (int port)                                                                根据端口号创建服务器端Socket对象

Socket accpet()                                                                             等待客户端连接并获得与客户端相关的Socket对象

ServerSocket ss = new ServerSocket(8989);
Socket s = ss.accept();

 

 

先完成简单的客户端程序与服务器之间以IO流的形式传输数据的功能实现

TCP服务器:

ServerSocket ss = new ServerSocket(8989);
Socket s = ss.accept();
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
System.out.println(s.getInetAddress() + "连接成功");
int len = 0;
byte[] b = new byte[1024];
while ((len = in.read(b)) != -1) {
    System.out.println(new String(b, 0, len));
}

TCP客户端:

Socket s = new Socket(InetAddress.getLocalHost(), 8989);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
out.write("申请连接".getBytes());
out.flush();
s.shutdownOutput();
s.close();

服务器接受到客户端发来的申请连接如图:

TCP的连接在客户端创建Socket对象时要传入服务器IP地址和端口号

然后利用Socket的方法获取输入输出流,根据IO流的传输手段,将信息或在服务器之间传输

 

 

若想让服务器能一直开启,并且接受多个客户端从本地上传到客户端再发送到服务器的文件

则需要运用到多线程开启服务器,且使用FileInputStream和FileOutputStream保存文件到服务器端的硬盘中

创建一个线程类继承Thread:

public class MyThread extends Thread {
    private Socket s;

    public MyThread(Socket s) {
        this.s = s;
    }

    public void run() {
        try {
            InputStream in = s.getInputStream();
            OutputStream out = s.getOutputStream();
            FileOutputStream fos = new FileOutputStream("zz.txt");
            System.out.println(s.getInetAddress() + "连接成功");
            int len = 0;
            byte[] b = new byte[1024];
            while ((len = in.read(b)) != -1) {
                fos.write(b, 0, len);
            }
        } catch (Exception e) {
        }
    }
}

主程序中:

ServerSocket ss = new ServerSocket(8989);
while (true) {
    Socket s = ss.accept();
    MyThread mt = new MyThread(s);
    mt.run();
}

将ServerSocket的accept()放在开启线程死循环的第一条,

由于accept()方法本身就有等待客户端连接动作,所以直到有客户端连接时才会开启MyThread线程

不会造成死循环开好线程等待客户连接的浪费资源情况

 

TCP客户端:

Socket s = new Socket();
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
FileInputStream fis = new FileInputStream("c.txt");
int len = 0;
byte[] b = new byte[1024];
while ((len = fis.read(b)) != -1) {
    out.write(b, 0, len);
}
s.shutdownOutput();
s.close();

客户端从本地磁盘中上传文件时,默认是读取文件字节到-1时结束

然后再在此循环中将这些字节发给服务器,当文件字节读到-1时已经结束发送了

那么客户端在上传给服务器的时候,并没有一个-1的值来当做结束标记,让服务器知道客户端已经上传完毕

所以客户端在上传完毕文件或者传输完信息时候

需要调用Socket的shutdownOutput()方法来告知服务器,已经不会再传输任何东西

 

先开启多线程服务器,然后再启用客户端发送c.txt文本

发现文本发送完成后,服务器仍在运行等待下一个客户端连接

且从根目录中上传的c.txt也已经从客户端发送到服务器再下载到根目录下保存为zz.txt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值