java基础——网路编程

网路编程常用对象:
InetAddress DatagramPacket DatagramSocket
ServerSocket Socket URL URLConnection

InetAddress用于获取ip地址(本地回环地址:127.0.0.1 主机名:localhost)

import java.net.*;
class  IPDemo
{
    public static void main(String[] args) throws Exception
    {
        InetAddress i = InetAddress.getLocalHost();
        System.out.println(i.toString());
        System.out.println("address:"+i.getHostAddress());
        System.out.println("name:"+i.getHostName());
    }
}

网络传输协议:TCP和UDP
UDP:
将数据及源和目的封装到数据包中,不需要建立连接,面向无连接。因为无连接,所以是不可靠协议,不需要建立连接速度快,每个数据包的大小限在64k内
TCP:
建立连接,形成传输数据通道,在连接中可以实现大量数据的传输,是可靠协议,因需建立连接,效率稍慢

聊天(UDP传输)
需要用到多线程,一个线程负责发送数据,另一个线程负责接收数据,因为收和发动作是不一致的,所以要定义两个run方法。而且这两个方法要封装到不同的类中。
数据的发送和接收
发送:
1.建立socket服务
2.写入数据并将数据打包为数据包
3.将数据包发送出去
4.关闭资源
接收:
1.建立socket服务,并与指定的发送端相关联
2.创建一个数据包,用来接收数据
3.将接收到的数据进行处理
4.关闭资源

import java.io.*;
import java.net.*;
class Send implements Runnable
{
    public void run()
    {
        DatagramSocket ds = null;
        try
        {
            //建立服务,可以指定一个端口号
            ds = new DatagramSocket();
            //写入数据,并将数据打包
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while ((line=bufr.readLine())!=null)
            {
                if("over".equals(line))
                    break;

                byte[] buf = line.getBytes();
                DatagramPacket dp = 
                    new DatagramPacket(buf,buf.length,InetAddress.getByName("172.25.85.2"),10001);
                //将数据包发送出去
                ds.send(dp);
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("数据发送失败");
        }
        //关闭资源
        ds.close();
    }
}
class Rece implements Runnable 
{
    public void run()
    {   
        try
        {
            //建立socket服务,并与发送端相关联
            DatagramSocket ds = new DatagramSocket(10001);
            while (true)//接收端可以一直开着,不用关
            {
                //创建一个数据包,用来接收一定长度的数据
                byte[] buf = new byte[1024];
                DatagramPacket dp = new DatagramPacket(buf,buf.length);

                //将接收的数据存储到数据包中,并进行相关的操作
                ds.receive(dp);
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(),0,dp.getLength());
                System.out.println(ip+"...."+data);
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("数据接收失败");
        }
    }
}
class ChatDemo
{
    public static void main(String[] args) throws Exception
    {
        new Thread(new Rece()).start();
        new Thread(new Send()).start();
    }
}

TCP:
建立一个文本转换服务器。
客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。
而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
客户端:
1,建立服务。
2,获取键盘录入。
3,将数据发给服务端。
4,后去服务端返回的大写数据。
5,结束,关资源。
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。
服务端:
1.建立服务端,并关联客户端的端口
2.通过accept方法,获取客户端的对象
3.获取客户端的输入流,用来读取来自客户端的数据
4.获取客户端的输出流,用来写反馈给客户端的数据
5.关闭客户端
6.关闭服务端(可选)

import java.io.*;
import java.net.*;
class  TransClient
{
    public static void main(String[] args) throws Exception
    {
        Socket s = new Socket("172.25.85.2",10002);

        //读取键盘数据的流对象。
        BufferedReader bufr = 
            new BufferedReader(new InputStreamReader(System.in));

        //定义目的,将数据写入到socket输出流。发给服务端。
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);

        //定义一个socket读取流,读取服务端返回的大写信息。
        BufferedReader bufIn = 
            new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;
        while((line=bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;

            out.println(line);//自带换行和刷新动作
            //读取来自服务端的数据
            String str =bufIn.readLine();
            System.out.println("server:"+str);
        }
        bufr.close();
        s.close();
    }
}
class  TransServer
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket ss = new ServerSocket(10002);

        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+"....已连接");

        //读取socket输出流中的数据。
        BufferedReader bufIn =
            new BufferedReader(new InputStreamReader(s.getInputStream()));

        //目的:socket输出流。将大写数据写入到socket输出流,并发送给客户端。
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);

        String line = null;
        while((line=bufIn.readLine())!=null)
        {
            out.println(line.toUpperCase());;
        }

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

该例子出现的问题。
现象:客户端和服务端都在莫名的等待。
因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等,从而导致两端都在等待。

需求:多个客户端同时发送文件
由于服务端的accept方法是一个阻塞式方法,且只有主线程执行,所以只能在一个客户端将代码执行完后才能获取下一个客户端对象,要进行多个客户端同时上传文件,需要多线程

import java.io.*;
import java.net.*;
class PicClient
{
    public static void main(String[] args) throws Exception
    {   
        //通过在运行时输入路径的方式传入图片
        if(args.length!=1)
        {
            System.out.println("请输入正确的路径");
            return ;
        }

        //将输入的路径封装成文件对象
        File file = new File(args[0]);
        if (!(file.exists() && file.getName().endsWith(".bmp")))
        {
            System.out.println("文件不存在或者不是bmp的文件");
            return ;
        }
        if (file.length()>1024*1024*10)
        {
            System.out.println("文件过大,请上传小于10M的图片");
            return ;
        }

        Socket s = new Socket("172.25.85.2",10010);
        /*
        BufferedReader bufr = 
            new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        BufferedWriter bufw =
            new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

        String line = null;
        while ((line=bufr.readLine())!=null)
        {
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }
        不能使用这样的方法进行读写,以一行为单位,会把没有数据的部分也写进去
        */

        FileInputStream fis = new FileInputStream(file);
        //将图片发送出去
        OutputStream out = s.getOutputStream();

        byte[] buf = new byte[1024];
        int len = 0;    
        while ((len=fis.read(buf))!=-1)
        {
            out.write(buf,0,len);
        }
        s.shutdownOutput();//加入一个结束标记

        //读取服务端发送过来的数据
        InputStream in = s.getInputStream();
        byte[] bufin = new byte[1024];
        int len1 = in.read(bufin);
        System.out.println(new String(bufin,0,len1));

        bufr.close();
        s.close();
    }
}
//把多线程需要执行的代码封装到run方法中
class PicThread implements Runnable
{
    private Socket s ;
    PicThread(Socket s)
    {
        this.s = s ;
    }
    public void run()
    {
        int count = 1 ;

        InetAddress i = s.getInetAddress();
        String ip = i.getHostAddress();
        System.out.println(ip+".....已连接");

        FileOutputStream fos = null;
        try
        {
            //以ip地址命名
            File file = new File(ip+"["+(count)+"]"+".jpg");

            //判断文件名是否存在,如果存在则将文件名自增后,再判断,直到文件名不在重复
            while (file.exists())
            {
                file = new File (ip+"["+(count++)+"]"+".jpg");
            }
            InputStream in = s.getInputStream();
            fos = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len=in.read(buf))!=-1)
            {
                fos.write(buf,0,len);
            }
            //向客户端发送信息,表示上传成功
            OutputStream out = s.getOutputStream();
            out.write("数据已上传成功".getBytes());
        }
        catch (Exception e)
        {
            throw new RuntimeException("数据上传失败");
        }
        finally
        {
            try
            {
                if(fos!=null)
                    fos.close();
                s.close();
            }
            catch (Exception e1)
            {
                throw new RuntimeException("资源关闭失败");
            }
        }
    }
}
class PicServer
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket ss = new ServerSocket(10010);
        while (true)
        {
            Socket s = ss.accept();
            new Thread(new PicThread(s)).start();
        }
    }
}

URL和URLConnection的应用:
可以直接把地址作为对象传入到URL的构造函数中,URL对象可以通OpenConnection方法创建URLConnection的对象,在URLConnection类中,有很多方法可以用来操作网页中的数据。
GUI和网络编程的相结合
在一个文本框中输入ip地址,通过点击按钮,将该网页中的内容打印到该窗体的文本区域中

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class WebGui
{
    private Frame f ;
    private TextField tf ;
    private TextArea ta ;
    private Button b ;

    WebGui()
    {
        init();
    }
    public void init()
    {
        f = new Frame("窗体");
        f.setBounds(300,150,500,400);
        f.setLayout(new FlowLayout());

        tf = new TextField(30);
        ta = new TextArea(15,60);
        b = new Button("转到");

        f.add(tf);
        f.add(b);
        f.add(ta);

        event();

        f.setVisible(true);
    }

    public void event()
    {
        //给按钮添加事件监听
        b.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                try
                {
                    show();
                }
                catch (Exception e1)
                {
                }
            }

        });
        f.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
        });
    }
    public void show() throws Exception
    {
        ta.setText("");
        //获取ip地址
        String ip = tf.getText();
        URL url = new URL(ip);
        //获取URLConnection对象
        URLConnection con = url.openConnection();
        InputStream in = con.getInputStream();
        byte[] buf = new byte[1024];
        int len = 0 ;
        while ((len=in.read(buf))!=-1)
        {
            //将网页中的数据添加到文本区域中
            ta.append(new String(buf,0,len));                                                                                                                                                                                                                                                                                                                        
        }
        in.close();
    }
    public static void main(String[] args) 
    {
        new WebGui();
    }
}

总结:在网络编程中较为常用的两种传输协议就是UDP和TCP传输,并且一般网络编程都会用到IO流。
对于UDP传输(发送端,接收端),由于其面向无连接的特性,它传输快,但不可靠,传输数据的大小也有限制,不能超过64k,关于UDP传输的应用,主要有聊天等
对于TCP传输(客户端,服务端),由于它必须要连接,所以具有可靠,传输数据量大的特点,相应的它的效率会稍慢。TCP的服务端想要获取客户端的数据,必须通过accept方法,获取客户端对象,关于TCP传输的应用,有下载等。一般的软件都会具备UDP和TCP两种传输通道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值