Java Socket

本文内容来自Java Socket应用—通信是这样练成的,记录下学习的内容

Java Socket

TCP/IP协议是目前应用最为广泛的协议,TCP传输控制协议,IP互联网协议。

应用层协议:

  • HTTP
  • FTP
  • SMTP简单邮件传送协议
  • Telnet远程登录服务

IP地址和端口号组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。

InetAddress

InetAddress类标识网络上的硬件资源,标识互联网协议(IP)地址。

获取InetAddress的实例
1.通过类方法获取

InetAddress address = InetAddress.getLocalHost();

2.根据机器名获取InetAddress实例

InetAddress address2 = InetAddress.getByName("WinfredZen");

3.根据IP地址来获取InetAddress实例

InetAddress address3 = InetAddress.getByName("192.168.0.1");

一些常用方法

方法说明
getHostName()获取计算机名
getHostAddress()获取IP地址

获取字节形式的IP地址

byte[] bytes = address.getAddress();
System.out.println("字节数组形式的IP:"+Arrays.toString(bytes));

URL

URL统一资源定位符,表示Internet上某一资源的地址。
URL由两部分组成:协议名称和资源名称,中间由冒号隔开。
java.net包中,提供了URL类来表示URL

构造方法

URL imooc = new URL("http://www.baidu.com");
URL url = new URL(imooc, "index.html?username=tom#test")

常用方法
示例说明使用上面创建的的url

方法说明示例
getProtocol()获取协议http
getHost()获取主机www.baidu.com
getPort()获取端口-1 java.net.URL.getPort()规定,若URL的实例未申明(省略)端口号,则返回值为-1
getPath()获取文件路径/index.html
getFile()获取文件名/index.html?username=tom
getRef()获取相对路径test
getQuery()获取查询字符串username=tom

使用URL读取网页内容
1.通过URL对象的openStream()方法可以得到指定资源的输入了
2.通过输入流可以读取、访问网络上的数据

如下:

    try {
        URL url = new URL("http://www.baidu.com");
        //获取URL对象所表示的资源的字节输入流
        InputStream in = url.openStream();
        //将字节输入流转换为字符输入流
        InputStreamReader isr = new InputStreamReader(in, "utf-8");
        //为字符输入流添加缓冲
        BufferedReader br = new BufferedReader(isr);
        //读取数据
        String data = br.readLine();
        while (data != null) {
            System.out.println(data);
            data = br.readLine();
        }
        br.close();
        isr.close();
        in.close();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

TCP

TCP协议是面向连接、可靠的、有序的,以字节流的方式发送数据。
Java中基于TCP协议实现网络通信的类
1.客户端的Socket
2.服务端的ServerSocket

Socket通信模型
Socket通信模型

Socket通信实现步骤
1.创建ServerSocketSocket
2.打开连接到Socket的输入/输出流
3.按照协议对Socket进行读/写操作
4.关闭输入输出流、关闭Socket

编程实现基于 TCP 的 Socket 通信

服务器端

1.创建ServerSocket对象,绑定监听端口
2.通过accept()方法监听客户端请求
3.连接建立后,通过输入流读取客户端发送的请求消息
4.通过输出流向客户端发送响应信息
5.关闭相关资源

package com.imooc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 服务端
 */
public class Server {

    public static void main(String[] args) {

        try {
            //创建服务端的socket
            ServerSocket serverSocket = new ServerSocket(8882);
            //调用accept()方法开始监听
            System.out.println("***服务器即将启动,等待客户端的连接***");
            Socket socket = serverSocket.accept();
            //获取输入流,读取客户端发送的登录信息
            InputStream is = socket.getInputStream();//字节输入流
            InputStreamReader isr = new InputStreamReader(is);//将字节流转为字符流
            BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
            String info = null;
            while ((info=br.readLine()) != null) {
                System.out.println("***我是服务器,客户端说:"+ info+"***");
            }
            //关闭输入流
            socket.shutdownInput();

            //获取输出流,响应客户端的请求
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            pw.write("欢迎您!");
            pw.flush();

            //关闭资源
            pw.close();
            os.close();
            br.close();
            isr.close();
            is.close();
            socket.close();
            serverSocket.close();
            System.out.println("服务端关闭连接");

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
客户端

1.创建Socket对象,指明需要连接的服务器的地址和端口号
2.连接建立后,通过输出流向服务器端发送请求消息
3.通过输入流获取服务器响应的消息
4.关闭相关资源

package com.imooc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

    public static void main(String[] args) {

        try {
            //创建socket,指定服务器地址和端口
            Socket socket = new Socket("localhost", 8882);
            //获取输出流,向服务器端发送登录信息
            OutputStream os = socket.getOutputStream();//字节输出流
            PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
            pw.write("用户名:admin;密码:123");
            pw.flush();
            //关闭输出流
            socket.shutdownOutput();

            //获取输入流
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info = null;
            while ((info=br.readLine()) != null) {
                System.out.println("***我是客户端,服务端说:"+ info+"***");
            }

            //关闭资源
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
            System.out.println("客户端关闭");

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
使用多线程实现多客户端的通信

应用多线程来实现服务器与多客户端之间的通信。
基本步骤:
1.服务端创建ServerSocket,循环调用accept()等待客户端连接
2.客户端创建一个socket并请求和服务端连接
3.服务端接受客户端请求,创建socket与该客户建立专线连接
4.建立连接的两个socket在一个单独的线程上对话

创建ServerThread类继承自Thread

package com.imooc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/*
 * 服务器线程处理类
 */
public class ServerThread extends Thread {

    private Socket socket = null;
    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;

        try {
            //获取输入流,读取客户端发送的登录信息
            is = socket.getInputStream();//字节输入流
            isr = new InputStreamReader(is);//将字节流转为字符流
            br = new BufferedReader(isr);//为输入流添加缓冲
            String info = null;
            while ((info=br.readLine()) != null) {
                System.out.println("***我是服务器,客户端说:"+ info+"***");
            }

            //关闭输入流
            socket.shutdownInput();

            //获取输出流,响应客户端的请求
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write("欢迎您!");
            pw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            try {
                if (pw != null) {
                    pw.close();
                }
                if (os != null) {
                    os.close();
                }
                if (br != null) {
                    br.close();
                }
                if (isr != null) {
                    isr.close();
                }
                if (is != null) {
                    is.close();
                }
                if (socket != null) {

                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }

}

服务器端代码:

package com.imooc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 服务端
 */
public class MutiServer {

    public static void main(String[] args) {

        try {
            //创建服务端的socket
            ServerSocket serverSocket = new ServerSocket(8882);
            System.out.println("***服务器即将启动,等待客户端的连接***");
            Socket socket = null;
            //记录连接数量
            int count = 0;
            //循环监听等待客户端的连接
            while (true) {
                //调用accept()方法开始监听
                socket = serverSocket.accept();
                //创建一个新的线程
                ServerThread serverThread = new ServerThread(socket);
                //启动线程
                serverThread.start();

                count++;
                System.out.println("连接数量:"+count);
                InetAddress address = socket.getInetAddress();
                System.out.println("客户单当前IP地址:"+address.getHostAddress());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

调试,控制台可能有如下的输出:

客户单当前IP地址:127.0.0.1
***我是服务器,客户端说:用户名:admin;密码:123***
连接数量:2
客户单当前IP地址:127.0.0.1
***我是服务器,客户端说:用户名:admin;密码:123***

编程实现基于 UDP 的 Socket 通信

UDP协议(用户数据报协议)是无连接、不可靠的、无序的
UDP协议以数据报作为数据传输的载体。
进行数据传输时,首先需要将要传输的数据定义成数据报(Datagram),在数据报中指明数据所要到达的Socket(主机地址和端口号),然后再将数据报发送出去。

相关的操作类

  • DatagramPacket表示数据包
  • DatagramSocket进行端到端通信的类
服务端

1.创建DatagramSocket,指定端口号
2.创建DatagramPacket,用来接收客户端发送的数据
3.接收客户端发送的数据信息
4.读取数据

package com.imooc;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/*
 * 服务端,实现基于UDP的用户登录
 */
public class UDPServer {

    public static void main(String[] args) throws IOException {
        /*
         * 接收客户端发送的数据
         */
        //创建服务端DatagramSocket,指定端口
        DatagramSocket socket = new DatagramSocket(8889);
        //创建数据报,用于接收客户端发送的数据
        byte[] data = new byte[1024];//创建字节数组,指定接收的数据包的大小
        DatagramPacket packet = new DatagramPacket(data, data.length);
        //接收客户端发送的数据
        socket.receive(packet);//此方法在接收到数据之前,会一直阻塞
        //读取数据
        String info = new String(data, 0, packet.getLength());
        System.out.println("我是服务器,客户端说:" + info);

        /*
         * 向客户端响应数据
         */
        //定义客户端的地址,端口号、数据
        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        byte[] dataToSend = "欢迎您".getBytes();
        //创建数据报,包含响应的数据信息
        DatagramPacket packet2 = new DatagramPacket(dataToSend, dataToSend.length,address, port);
        //响应客户端
        socket.send(packet2);
        //关闭资源
        socket.close();
    }

}
客户端

1.定义发送信息
2.创建DatagramPacket,包含我们要发送的信息
3.创建DatagramSocket,用来实现数据的发送
4.发送数据

package com.imooc;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

/*
 * 客户端实现
 */
public class UDPClient {

    public static void main(String[] args) throws IOException {
        /*
         * 向服务器发送数据
         */
        //定义服务器的地址、端口号
        InetAddress address = InetAddress.getByName("localhost");
        int port = 8889;
        byte[] data = "用户名:admin;密码:123".getBytes();
        //创建数据报,包含发送的数据
        DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
        //创建DatagramSocket对象
        DatagramSocket socket = new DatagramSocket();
        //向服务器发送数据报
        socket.send(packet);

        /*
         * 接收服务器响应数据
         */
        //创建数据报,用于接收数据端响应的数据
        byte[] data2 = new byte[1024];
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
        //接收服务器响应的数据
        socket.receive(packet2);
        //读取数据
        String reply = new String(data2,0, packet2.getLength());
        System.out.println("我是客户端,服务器说:"+reply);
        //关闭资源
        socket.close();
    }

}

总结

1.多线程的优先级
未设置优先级可能会导致运行时速度非常慢,可降低优先级
多线程的优先级

2.是否关闭输出流和输入流
对应同一个socket,如果关闭了输出流,则与该输出流关联的socket也会被关闭,所以一般不用关闭流,直接关闭socket即可
是否关闭输出流和输入流

3.使用TCP通信传输对象
使用TCP通信传输对象

4.socket编程传递文件
socket编程传递文件

Java Socket应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值