利用网络,实现两台计算机之间的互相联通、交互。


网络编程有两类:

UDP

一种无连接的传输层协议。无连接:指不需要知道对方在不在,只负责发数据传输出去,而对方可能不在,数据便会丢失,所以是不稳定的。

甩代码了!
发送:SendDemo.java

import java.net.*;
class SendDemo{
    public static void main(String[] args) throws Exception{
        //1.创建UDP服务,通过DatagramSocket对象
        DatagramSocket ds=new DatagramSocket(7878);
        //2.确定数据,并封装成数据包,DatagramPacket
        byte[] buf="nihao hong".getBytes();
        DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("10.73.131.122"),10000); //接受对象的ip(这里的ip写的是一个局域网内的ip,可以是本机)及端口
        //3.通过socket服务,将现有的数据包发出去,通过send方法
        ds.send(dp);
        //4.关闭资源,关闭的是使用网络的资源
        ds.close();
    }
}

接受:ReceiveDemo.java

import java.net.*;
class ReceiveDemo{
    public static void main(String[] args) throws Exception{
        //1.创建UDP socket,建立端点,设置接受者接收的端口
        DatagramSocket ds=new DatagramSocket(10000);

        while(true){
        //2.定义数据包,用于储存数据
        byte[] buf=new byte[1024];
        DatagramPacket dp=new DatagramPacket(buf,buf.length);
        //3.通过服务的receive方法将收到数据存入数据包中
        ds.receive(dp);
        //4.通过数据包的方法获取其中的数据
        String ip=dp.getAddress().getHostAddress();//获得ip地址
        String data=new String(dp.getData(),0,dp.getLength());
        int port=dp.getPort();//得到发送端的端口
        System.out.println(ip+"::"+data+"::"+port);
        }
        //5.关闭资源,我希望接收端能够一直接受,于是可以用死循环,但是由于死循环,代码无法走到这里,为图省事就注释了
        //ds.close();
    }
}

知识点,也是注意点
1. 由于这是UDP,是一种不可靠的连接,所以我们需要先运行接收端,这样才能够接受。
2. 开始在进行测试两台计算机之间的互联时,一直连接不上,我们需要关闭防火墙。

飞Q

听说这是一个能够在局域网内实现通信的工具。

接下来是模拟飞Q的命令行版。

需要使用多线程,同时运行”接受者”和”发送者”。
加上界面话之后,我觉得和飞Q就不远了。

继续甩一对代码:Receiver.java

import java.net.*;
import java.lang.*;
import java.io.*;
class Receiver{
    public static void main(String[] args) throws Exception{
        Thread t1=new Thread(new Send1());
        Thread t2=new Thread(new Rece1());
        t1.start();
        t2.start();
        // ds.close();
    }


}

class Send1 implements Runnable{
    @Override
    public void run(){
        try{
            DatagramSocket ds=new DatagramSocket();
            int len=0;
            // byte[] buf=new byte[1024];
            String buf;
            while(true){
                buf=new BufferedReader(new InputStreamReader(System.in,"utf-8")).readLine();
                // String str=new String(buf,0,len);
                DatagramPacket dp=new DatagramPacket(buf.getBytes(),buf.length(),InetAddress.getByName("10.73.131.122"),10000);
                ds.send(dp);
            }
        }catch (Exception e){
            throw new RuntimeException("发送失败");
        }
    }
}

class Rece1 implements Runnable{
    @Override
    public void run(){
        try{
        DatagramSocket ds=new DatagramSocket(10001);
        while(true){
            byte[] buf=new byte[1024];
            DatagramPacket dp=new DatagramPacket(buf,buf.length);
            ds.receive(dp);
            System.out.print("对方说:");
            System.out.println(new String(dp.getData(),0,dp.getLength(),"utf-8"));
            }
        }catch (Exception e){
            throw new RuntimeException("接受失败");
        }

    }
}

Sender.java

import java.net.*;
import java.lang.*;
import java.io.*;
class Sender{
    public static void main(String[] args) throws Exception{
        Thread t1=new Thread(new Send1());
        Thread t2=new Thread(new Rece1());
        t1.start();
        t2.start();
        // ds.close();
    }


}

class Send1 implements Runnable{
    @Override
    public void run(){
        try{
            DatagramSocket ds=new DatagramSocket();
            int len=0;
            // byte[] buf=new byte[1024];
            String buf;
            while(true){
                buf=new BufferedReader(new InputStreamReader(System.in,"utf-8")).readLine();
                // String str=new String(buf,0,len);
                DatagramPacket dp=new DatagramPacket(buf.getBytes(),buf.getBytes().length,InetAddress.getByName("10.73.132.176"),10001);
                ds.send(dp);
            }
        }catch (Exception e){
            throw new RuntimeException("发送失败");
        }
    }
}

class Rece1 implements Runnable{
    @Override
    public void run(){
        try{
        DatagramSocket ds=new DatagramSocket(10000);
        while(true){
            byte[] buf=new byte[1024];
            DatagramPacket dp=new DatagramPacket(buf,buf.length);
            ds.receive(dp);
            System.out.print("对方说:");
            System.out.println(new String(dp.getData(),0,dp.getLength(),"utf-8"));
            }
        }catch (Exception e){
            throw new RuntimeException("接受失败");
        }

    }
}

知识点
1.这里是需要有两台机子相互通信,接收端需要设置义自己接受信息的端口,发送端需要设置自己发送目标的ip地址和端口
2.两台电脑间传输后可能会出现乱码的现象,不过往往是由于编译器不同引起的。大致原因有两个,一个是在键盘键入(System.in)时不同的编译器不同,所以可以使用转换流,将输入的内容的字节,通过指定的字符编码,将键入内容转化为相应编码的字符,再变为字节传输。另一个,接受时,接受的也是字节流,我们也可以用指定的字符编码进行读取。(InputStreamReader)
3.其实一个“发送”涉及输入流和输出流,一个输入流:从键盘得到数据,一个输出流:打包发送。

TCP

一种面向连接的、可靠的、基于字节流的传输层通信协议。需要三次握手。
三次握手,两次是客户端发给服务端的,中间隔了一次服务端发送给客户端。

需求,客户端给服务端发送消息,并能得到服务端的反馈。
甩代码:TcpServer2

import java.io.*;
import java.net.*;
class TcpServer2{
    public static void main(String[] args) throws Exception{
        ServerSocket ss=new ServerSocket(10023);
        Socket s=ss.accept();
        System.out.println(s.getInetAddress().getHostAddress()+".....connection");
        InputStream in=s.getInputStream();
        byte[] buf=new byte[1024];
        int len;
        len=in.read(buf);
        System.out.println(new String(buf,0,len));
        OutputStream out=s.getOutputStream();
        out.write("我这收到啦!你也好".getBytes());
        s.close();
        ss.close();
    }
}

TcpClient2java

import java.io.*;
import java.net.*;
class TcpClient2{
    public static void main(String[] args) throws Exception{
        Socket s=new Socket("10.73.131.122",10023);
        OutputStream out=s.getOutputStream();
        out.write("你好 服务端".getBytes());
        InputStream in=s.getInputStream();
        byte[] buf=new byte[1024];
        int len;
        len=in.read(buf);
        System.out.println(new String(buf,0,len));
        s.close();
    }
}

知识点

由于这是可靠的TCP协议,客户端需要先和服务端建立连接,所以还是需要服务端先运行,当然,如果服务端未运行,或者在客户端运行过程中服务端挂了,那么,在客户端就会抛异常,由于可靠的连接被中断了。

下面的需求是客户端向服务端发送文件,文件传输结束后,给客户端返回传输成功信号
TextServer.java

import java.net.*;
import java.io.*;
class TextServer{
    public static void main(String[] args) throws Exception{
        ServerSocket ss=new ServerSocket(10023);
        Socket s=ss.accept();
        BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
        PrintWriter pw=new PrintWriter(new FileWriter("server.txt"),true);
        String str;
        while((str=br.readLine())!=null){
            pw.println(str);
        }
        PrintWriter out=new PrintWriter(s.getOutputStream(),true);
        out.println("上传成功");

        pw.close();
        s.close();
        ss.close();
    }
}

TextClient.java

import java.io.*;
import java.net.*;
class TextClient{
    public static void main(String[] args) throws Exception{
            Socket s=new Socket("10.73.131.122",10023);
            BufferedReader in=new BufferedReader(new FileReader("TcpServer2.java"));
            PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
            String str=null;
            while((str=in.readLine())!=null){
                pw.println(str);
            }
            s.shutdownOutput();
            BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
            String result=br.readLine();
            System.out.println(result);
            in.close();
            s.close();
        }   
}

这里使用了PrintWriter,好处:字符流和字节流都可以直接写,而且可以实现续写 new PrintWriter(s.getOutputStream(),true) 定义的时候设置。

需求:客户端发送给服务端文字,服务端经过特殊处理(变成全大写返回),返回给客户端,在客户端输出。
TransServer.java

import java.io.*;
import java.net.*;
class TransServer{
    public static void main(String[] args) throws Exception{
        ServerSocket ss=new ServerSocket(10023);
        Socket s=ss.accept();
        System.out.println(s.getInetAddress().getHostAddress()+"....connect");
        BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String str=null;
        while((str=br.readLine())!=null){
            String newStr=str.toUpperCase();
            System.out.println("reply:"+newStr);

            out.write(newStr);
            out.newLine();
            out.flush();
        }
        s.close();
        ss.close();
    }
}

TransClient.java

import java.io.*;
import java.net.*;
class TransClient{
    public static void main(String[] args) throws Exception{
        Socket s=new Socket("10.73.131.122",10023);
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String str;
        while((str=br.readLine())!=null){
            if("over".equals(str)){
                break;
            }
            out.write(str);
            out.newLine();
            out.flush();

            BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
            String result=in.readLine();
            System.out.println(result);
        }
        br.close();
        s.close();
    }
}

总结:

当客户端和服务端分离时,我们需要通过网络传输。