java的TCP\IP编程

导读:本篇文章讲解 java的TCP\IP编程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

本文主要讲述java的网络知识,以及网络编程所需要使用的类。

一. InetAdress类

InetAddress类,用于获取主机名和IP地址【域名】

public class InetAddressTest {
    public static void main(String[] args) throws UnknownHostException {
        // 1.获取本机的Inet4Address对象
        InetAddress localHost = Inet4Address.getLocalHost();
        System.out.println("本地主机的InetAddress对象: " + localHost);
        // 2.根据主机的名称,获取Inet4Address对象
        InetAddress host1 = Inet4Address.getByName("DESKTOP-TIT5KO3");
        System.out.println("本地主机的InetAddress对象: " + host1);
        // 3.根据域名,获取InetAddress对象
        InetAddress host2 = Inet4Address.getByName("www.baidu.com");
        System.out.println("百度的InetAddress对象: " + host2);
        // 4.根据InetAddress对象,获取IP地址
        String hostAddress = host2.getHostAddress();
        System.out.println("IP地址: " + hostAddress);
        // 5.根据InetAddress对象,获取主机名\域名
        String hostName = host2.getHostName();
        System.out.println("域名: " + hostName);
    }
}

二. Socket类

案例一:使用字节流,编写服务端和客户端,要求服务端接受客户端发过来的数据,并显示在控制台上

服务端:

public class SocketTCPServer {
    public static void main(String[] args) throws Exception{
        // 1. 服务端,创建ServerSocket对象,在本主机监听9999端口,等待客户端的链接
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端的serverSocket正在监听9999端口,等待连接");
        // 2. 客户端如果链接了9999端口,返回socket对象;否则,程序阻塞,无法向下执行
        //    serverSocket.accept()会返回多个Socket【多个客户端并发】
        Socket socket = serverSocket.accept();
        System.out.println("服务器端返回的serverSocket: " + socket.getClass());
        // 3. 客户端socket对象写入数据,服务端socket对象获取输入流 getOutputStream,读入数据
        InputStream inputStream = socket.getInputStream();
        // 4. 使用inputStream读取数据
        byte[] bytes = new byte[1024]; // 读取数据所需要的字节数组
        int readLen = 0; // 读取数据的长度
        // 读取长度是-1,则表示数据已经读完
        while((readLen = inputStream.read(bytes)) != -1){
            // 每次按照bytes数组长度,读取数据内容,读取完毕,返回-1.
            // new String(bytes,0,readLen),防止不足bytes数组长度的数据无法显示
            System.out.print(new String(bytes,0,readLen));
        }
        System.out.println("服务器端读取数据完毕");
//         5. 关闭输入流和socket【服务端】
        inputStream.close();
        socket.close();
        serverSocket.close();

    }
}

客户端:

public class SocketTCPClient01 {
    public static void main(String[] args) throws Exception{
        // 1. 客户端,创建socket对象 new Socket(ip地址,端口号)
        // ip地址,是服务端所在主机的ip地址,端口号是服务端监听的端口号
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端返回的serverSocket: " + socket.getClass());
        // 2. 通过socket对象,获取socket的输出流getOutputStream(),写入数据
        OutputStream outputStream = socket.getOutputStream();
        // 3. 使用OutputStream写入数据
        outputStream.write("hello,I am client01\n".getBytes());
        // 4. 关闭输出流和socket【客户端】
        outputStream.close();
        socket.close();
//        System.out.println("客户端退出");

    }
}

案例二:使用字节流,编写服务端和客户端,要求服务端接收客户端的消息A,发送消息B;客户端发送消息A,接收服务端的消息B

vip

错误写法:

服务端:

public class SocketServer {
    public static void main(String[] args) throws Exception{
        // 1. 创建socketServer对象,端口号9999
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("启动服务器...");
        // 2. 监听客户端
        Socket socket = serverSocket.accept();
        // 3. 获取输入流
        InputStream inputStream = socket.getInputStream();
        int readLen = 0;
        byte[] bytes = new byte[1024];
        while((readLen = inputStream.read(bytes)) != -1){
            String s = new String(bytes, 0, readLen);
            System.out.println(s);
        }
        // 4. 获取输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello Client".getBytes());// 5. 关闭输入输出流
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客户端:

public class SocketClient01 {
    public static void main(String[] args) throws IOException {
        // 1. 创建socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("启动客户端...");
        // 2. 获取OutPut
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello Server".getBytes());
        // 3. 获取输入流
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int readLen = 0;
        while((readLen = inputStream.read(bytes)) != -1){
            String s = new String(bytes, 0, readLen);
            System.out.println(s);
        }
        // 4. 关闭输入输出流
        outputStream.close();
        inputStream.close();
        socket.close();
    }
}

此时,启动服务端,监听客户端是否链接,启动客户端,在客户端写入hello Server,服务端读取到了数据,并将其显示,但是服务端并不知道客户端在什么时候写入结束,因此服务端会在数据连接中一直进行读操作,客户端在等待接收服务端写入的数据,随即发生了服务端和客户端都阻塞的现象。

正确写法:

// 设置输出的结束标记
socket.shutdownOutput();
// 设置输入的结束标记
socket.shutdownInput();

当写入或者读取结束时,要设置写入或者读取结束的标记

服务端:

public class SocketServer {
    public static void main(String[] args) throws Exception{
        // 1. 创建socketServer对象,端口号9999
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("启动服务器...");
        // 2. 监听客户端
        Socket socket = serverSocket.accept();
        // 3. 获取输入流
        InputStream inputStream = socket.getInputStream();
        int readLen = 0;
        byte[] bytes = new byte[1024];
        while((readLen = inputStream.read(bytes)) != -1){
            String s = new String(bytes, 0, readLen);
            System.out.println(s);
        }
        // 设置输入结束的标记
        socket.shutdownInput();
        // 4. 获取输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello Client".getBytes());
        // 设置输出的结束标记
        socket.shutdownOutput();

        // 5. 关闭输入输出流
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客户端:

public class SocketClient01 {
    public static void main(String[] args) throws IOException {
        // 1. 创建socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("启动客户端...");
        // 2. 获取OutPut
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello Server\n".getBytes());
        // 设置输出的结束标记
        socket.shutdownOutput();
        // 3. 获取输入流
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int readLen = 0;
        while((readLen = inputStream.read(bytes)) != -1){
            String s = new String(bytes, 0, readLen);
            System.out.println(s);
        }
        // 设置输入的结束标记
        socket.shutdownInput();
        // 4. 关闭输入输出流
        outputStream.close();
        inputStream.close();
        socket.close();
    }
}

运行结果:

vip

vip

 案例三:使用字符流,编写服务端和客户端,要求服务端接收客户端的消息A,发送消息B;客户端发送消息A,接收服务端的消息B。

通过socket只能获得字节流,因此需要转换流,将原本的字节流转换成字符流

服务端:

@SuppressWarnings({"all"})
public class SocketTCPServer {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务器开始启动...");
        Socket socket = serverSocket.accept();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str = null;
        while((str = br.readLine()) != null){
            System.out.println(str);
        }
        socket.shutdownInput();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"utf-8"));
        bw.write("hello client\n");
        bw.write("I am server");
        bw.flush();
        socket.shutdownOutput();
        br.close();
        bw.close();
        socket.close();
        serverSocket.close();
    }
}

客户端:

@SuppressWarnings({"all"})
public class SocketTCPClient {
    public static void main(String[] args) throws Exception{
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端开始启动...");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
        bw.write("hello server\n");
        bw.write("I am client");
        bw.flush();
        socket.shutdownOutput();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str = null;
        while((str = br.readLine()) != null){
            System.out.println(str);
        }
        socket.shutdownInput();
        bw.close();
        br.close();
        socket.close();
    }
}

注意:在写入数据后,使用处理流bw.flush(),手动刷新,将写入的数据放入数据通道。

运行结果:

vip

vip

 案例四:使用字节流,客户端向服务端传输图片,传送完成,服务端在src下保存图片,并且向客户端发送“收到图片”

vip

注意:写入数据通道内容后,手动刷新以及添加写入和读取的结束标志。

服务端:

@SuppressWarnings({"all"})
public class SocketServer01 {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务器监听");
        Socket socket = serverSocket.accept();
        // 1.获取socket对象的输入流
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        // 2.获取输出流,写入数据
        String filePath = "src\\111.jpg";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        int readLen = 0;
        byte[] bytes = new byte[1024];
        while((readLen = bis.read(bytes)) != -1){
            bos.write(bytes,0,readLen);
        }
        socket.shutdownInput();
        BufferedOutputStream boss = new BufferedOutputStream(socket.getOutputStream());
        boss.write("收到图片".getBytes());
        boss.flush();
        socket.shutdownOutput();

        bis.close();
        bos.close();
        boss.close();
        socket.close();
        serverSocket.close();

    }
}

客户端:

@SuppressWarnings({"all"})
public class SocketClient01 {
    public static void main(String[] args) throws Exception{
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端开始启动");
        // 1.获取socket的输出流->处理流
        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);
        // 2.获取socket的输入流->处理流
        String filePath = "F:\\desk.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
        int readLen = 0;
        byte[] bytes = new byte[1024];
        while((readLen = bis.read(bytes)) != -1){
            bos.write(bytes,0,readLen);
        }
        // 循环写入的话,需要将输出流不断地刷新,否则数据传输不完整
        bos.flush();
        socket.shutdownOutput();

        BufferedInputStream biss = new BufferedInputStream(socket.getInputStream());
        while((readLen = biss.read(bytes)) != -1){
            System.out.println(new String(bytes,0,readLen));
        }
        bos.close();
        bis.close();
        biss.close();
        socket.close();
    }
}

运行结果:

vip

vip vip

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98953.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!