网络编程

  • 网络模型
  • OSI参考模型
  • TCP/IP参考模型
  • 网络通讯要素
  • IP地址
  • 端口号
  • 传输协议

网络通讯要素

  • 网络中设备的标识
  • 不易记忆,可用主机名
  • 本地回环地址: 127.0.0.1 主机名: localhost
  • 端口号
  • 用于标识进程的逻辑地址,不同进程的标识
  • 有效端口:0~65535,其中0~1024系统使用或保留端口
  • 传输协议
  • 通讯的规则
  • 常见协议:TCP,UDP

TCP和UDP

  • UDP
  • 将数据及源和目的封装成数据包中,不需要建立连接
  • 每个数据报的大小限制在64K内
  • 因无连接,是不可靠协议
  • 不需要建立连接,速度快
  • TCP
  • 建立连接,形成传输数据的通道
  • 在连接中进行大数据量传输
  • 通过三次握手完成连接,是可靠协议
  • 必须建立连接,效率会稍低

Socket

  • Socket就是为网络服务提供的一种机制
  • 通信的两端都有Socket
  • 网络通信其实就是Socket间的通信
  • 数据在两个Socket间通过IO传输

UDP 发送接收

UDP发送端

import java.net.*;
class UdpDemo
{
    public static void main(String[] args) throws Exception
    {
        String data="hello";
        //确定数据,并封装成数据包
        byte[] b=data.getBytes();
        InetAddress ia=InetAddress.getByName("192.168.0.104");
        //1.创建UDP服务,通过DatagramSocket对象
        DatagramSocket ds=new DatagramSocket();
        //封装成数据包
        DatagramPacket dp=new DatagramPacket(b,b.length,ia,10000);
        //通过socket服务,将已有的数据包发送出去通过send方法
        ds.send(dp);
        //关闭资源
        ds.close();
    }
}

UDP接收端

import java.net.*;
class UdpReceive
{
    public static void main(String[] args) throws Exception
    {
        byte[] b=new byte[1024];
        DatagramSocket ds=new DatagramSocket(10000);
        DatagramPacket dp=new DatagramPacket(b,1024);
        ds.receive(dp);
        System.out.println(dp.getAddress().getHostAddress());
        System.out.println(dp.getPort());
        System.out.println(new String(dp.getData(),0,dp.getLength()));
        ds.close();
    }
}

重复接收,通过键盘输入发送数据

发送端

import java.net.*;
import java.io.*;
class UdpSender
{
    public static void main(String[] args) throws Exception
    {
        String data="";
        //确定数据,并封装成数据包
        InetAddress ia=InetAddress.getByName("192.168.0.104");
        //1.创建UDP服务,通过DatagramSocket对象
        DatagramSocket ds=new DatagramSocket();
        //通过socket服务,将已有的数据包发送出去通过send方法
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
        while(true)
        {
            data=bufr.readLine()
            //封装成数据包
            byte[] buf=data.getBytes();
            DatagramPacket dp=new DatagramPacket(buf,buf.length,ia,10000);
            ds.send(dp);
            if(data.equals("bye"))
                break;
        }
        //关闭资源
        ds.close();
    }
}

接收端

import java.net.*;
class UdpReceive
{
    public static void main(String[] args) throws Exception
    {
        byte[] buf=new byte[1024];
        String senderAddress="";
        String data="";
        int senderPort=0;
        int dataLength=0;
        DatagramSocket ds=new DatagramSocket(10000);
        DatagramPacket dp=new DatagramPacket(buf,1024);
        while(true)
        {
            ds.receive(dp);
            senderAddress=dp.getAddress().getHostAddress();
            senderPort=dp.getPort();
            dataLength=dp.getLength();
            data=new String(dp.getData(),0,dataLength);

            System.out.println(senderAddress+":"+senderPort+" "+data);
            if(data.equals("bye"))
                break;

        }
        ds.close();
    }
}

UDP 实现聊天

  • 创建一个客户端,一个服务端
  • 分别绑定到10000和20000端口
  • 创建两个线程
  • 1个接收线程
  • 通过提供的Socket和绑定的端口监听消息,并显示
  • 1个发送线程
  • 通过提供的Socket和绑定的端口发送消息到包 DatagramPacket 指定的地址和端口

UDP聊天程序1

import java.net.*;
import java.io.*;
//接受消息线程
class RecRun implements Runnable
{
    DatagramSocket ds;

    String data;

    RecRun(DatagramSocket ds)
    {
        this.ds=ds;

    }
    public void run()
    {
        while(true)
        {
            try
            {

                byte[] bufr=new byte[1024];
                DatagramPacket dp=new DatagramPacket(bufr,bufr.length);
                ds.receive(dp);

                data=new String(dp.getData(),0,dp.getLength());
                System.out.println("");

                System.out.println(dp.getAddress().getHostAddress()+":"+dp.getPort()+" 说:");
                System.out.println(data);

                System.out.println("");
                if(data.equals("bye"))
                {
                    System.out.println("对方结束了通话,回车退出.");
                    break;
                }
            }
            catch(Exception e)
            {
                //e.printStackTrace();
                break;
            }
        }
        ds.close();
    }
}
//发送消息线程
class SendRun implements Runnable
{
    DatagramSocket ds;
    DatagramPacket dp;
    String line;
    SendRun(DatagramSocket ds,DatagramPacket dp)
    {
        this.ds=ds;
        this.dp=dp;
    }
    public void run()
    {
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
        while(true)
        {

            try
            {
                System.out.println("请输入:");
                line=bufr.readLine();

                dp.setData(line.getBytes());
                ds.send(dp);
            }
            catch(Exception e)
            {

                break;
            }
            if(line.equals("bye"))
                break;
        }
        ds.close();
    }
}
class ChatServer
{
    public static void main(String[] args) throws Exception
    {
        //创建发送目的包
        int port=20000;
        byte[] buf=new byte[1024];
        InetAddress ia=InetAddress.getByName("192.168.0.104");
        DatagramPacket dp=new DatagramPacket(buf,buf.length,ia,port);

        //创建套接字,绑定本地端口号
        DatagramSocket ds=new DatagramSocket(10000);

        //接收包


        //创建接收消息线程,根据绑定的端口号进行监听
        Thread recThread=new Thread(new RecRun(ds));
        //创建发送消息线程,通过绑定的端口进行发送,发送到DatagramPacket 中 InetAddress 的IP地址和port端口号提供的接收地址.
        Thread sendThread=new Thread(new SendRun(ds,dp));

        recThread.start();
        sendThread.start();
    }
}

UDP聊天程序2

import java.net.*;
import java.io.*;

class ChatClient
{
    public static void main(String[] args) throws Exception
    {

        byte[] bufs=new byte[1024];
        //发送到的端口
        int port=10000;
        //发送到的地址
        InetAddress ia=InetAddress.getByName("192.168.0.104");
        //套接字
        DatagramSocket ds=new DatagramSocket(20000);

        DatagramPacket dps=new DatagramPacket(bufs,bufs.length,ia,port);;


        Thread recThread=new Thread(new RecRun(ds));
        Thread sendThread=new Thread(new SendRun(ds,dps));

        recThread.start();
        sendThread.start();
    }
}

TCP

tcp分客户端和服务端
客户端对应的对象是Socket
服务端对应的对象是ServerSocket

客户端
通过查阅Socket对象,发现在该对象建立时,就可以去连接指定主机
因为tcp是面向连接的,所以在建立socket服务时,就要有服务端存在,并连接成功,形成通路后,在该通道进行数据传输。

TCP服务端

import java.net.*;
import java.io.*;

class TcpServer
{
    public static void main(String[] args) throws Exception
    {

        //创建一个服务端socket,绑定本机端口20000
        ServerSocket mySocket=new ServerSocket(20000);

        //通过accept方法获取连接过来的客户端对象
        Socket cSocket=mySocket.accept();
        //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据

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

        InputStream in=cSocket.getInputStream();

        byte[] buf=new byte[1024];
        int len=in.read(buf);
        String data=new String(buf,0,len);

        System.out.println(data);

        //关闭客户端

        cSocket.close();

        mySocket.close();

    }
}

TCP客户端

import java.net.*;
import java.io.*;

class TcpClient
{
    public static void main(String[] args) throws Exception
    {
        //创建客户端的socket服务,指定目的主机和端口
        Socket cSocket=new Socket("192.168.0.104",20000);
        OutputStream out=cSocket.getOutputStream();
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
        String str=bufr.readLine();
        out.write(str.getBytes());

        cSocket.close();
    }
}

TCP阻塞式聊天

1.服务器启动,等待客户端连接
2.客户端连接,然后等待用户输入
3.用户输入信息,回车发送,客户端进入等待,等待服务器发送信息
4.服务器接受消息,并显示
5.服务器进入阻塞状态,等待用户输入信息
6.服务器发送信息给客户端
7.服务器进入等待,客户端收到信息并显示.

import java.io.*;
import java.net.*;

class TcpChatServer
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket sSocket=new ServerSocket(20000);
        Socket cSocket=sSocket.accept();
        String ip=cSocket.getInetAddress().getHostAddress();
        System.out.println(ip+"已连接");
        //键盘输入流
        BufferedReader kBufR=
            new BufferedReader(new InputStreamReader(System.in));
        //网络输入流
        BufferedReader bufR=
            new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
        //网络输出流
        BufferedWriter bufW=
            new BufferedWriter(new OutputStreamWriter(cSocket.getOutputStream()));
        String line;
        String lineInput;

        while((line=bufR.readLine())!=null)
        {
            if(line.equals("over"))
                break;
            System.out.println(ip+": "+line);
            lineInput=kBufR.readLine();
            bufW.write(lineInput);
            bufW.newLine();
            bufW.flush();


        }
        kBufR.close();
        cSocket.close();
        sSocket.close();
    }
}
class TcpChatClient
{
    public static void main(String[] args) throws Exception
    {
        Socket cSocket=new Socket("192.168.0.104",20000);
        //键盘输入流
        BufferedReader kBufR=
            new BufferedReader(new InputStreamReader(System.in));
        //网络输入流
        BufferedReader bufR=
            new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
        //网络输出流
        BufferedWriter bufW=
            new BufferedWriter(new OutputStreamWriter(cSocket.getOutputStream()));

        String line;
        String data;
        while((line=kBufR.readLine())!=null)
        {
            if(line.equals("over"))
                break;
            bufW.write(line);
            bufW.newLine();
            bufW.flush();
            data=bufR.readLine();
            System.out.println("服务器说:"+data);
        }
        kBufR.close();
        cSocket.close();

    }

}

URL

URL(String spec)
根据 String 表示形式创建 URL 对象。

String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部分。
URLConnection openConnection()
返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。

URLConnection

直接已知子类:
HttpURLConnection, JarURLConnection
InputStream getInputStream()
返回从此打开的连接读取的输入流。
OutputStream getOutputStream()
返回写入到此连接的输出流。
通过流对象可以像socket一样进行http通讯
通过getInputStream获取输入流可以从服务器获得网页源文件