秋日的晚霞 2021-10-27 20:30 采纳率: 94.4%
浏览 15
已结题

求解Address already in use: JVM_Bind TCP客户端服务端案例报错 静态代码块多次执行

客户端


package client;

import server.Server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Scanner;

public class Cilent {
    public static void main(String[] args) throws IOException {

        Socket sk = new Socket(InetAddress.getLocalHost(), 10261);

        InputStream is = sk.getInputStream();
        OutputStream os = sk.getOutputStream();

        //发送数据
        byte[] bytes = new byte[1024];
        int len;

        //获取输出,输出流
        Scanner sc = new Scanner(System.in);

        System.out.println("请选择选项   1 进入聊天室   2 传送文件到服务端   3 退出");
        String nextInt = sc.nextLine();
        //进入聊天室
        if (nextInt.equals("1")) {

            System.out.println("系统:请输入用户名");
            String name = sc.nextLine();
            System.out.println("系统:请输入密码");
            String password = sc.nextLine();
            os.write(name.getBytes());
            os.write(password.getBytes());

            //获取服务器返回结果信息
            bytes=new byte[1024];

            len=is.read(bytes);

            String result = new String(bytes, 0, len);
            System.out.println("result = " + result);
            if (result.contains("成功")) {

                while (true) {
                    System.out.println("系统:请发送消息给服务端" + new Date());
                    String outmessage = sc.nextLine();
                    os.write(outmessage.getBytes());

                    if (outmessage.contains("退出")) {
                        //退出
                        os.write("退出聊天".getBytes());
                        break;
                    }
                    //获取服务器返回的消息
                    System.out.println("等待服务器返回消息");
                    bytes=new byte[1024];
                    len=is.read(bytes);
                    String inString = new String(bytes, 0, len);
                    System.out.println("接受的服务器消息 : "+inString);
                }

            }else {
                sk.close();
                return;
            }


        }else {
            //todo
            //通知服务器减少一个连接,报错
            Server.num.decrementAndGet();
            sk.close();
        }


    }
}

服务端


package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Server {

    private static ServerSocket ss;

     public static AtomicInteger num=new AtomicInteger(1);

    static {
        //创建服务端程序
        System.out.println("服务端套接字对象创建");
        try {
            ss = new ServerSocket(10261);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        //使用线程池,支持多个客户端连接

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                10,
                20,
                24,
                TimeUnit.HOURS,
                new ArrayBlockingQueue<>(100),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

        //开启10个线程
//        while (threadPoolExecutor.getActiveCount() < 10) {
//            //提交任务
//             threadPoolExecutor.submit(new Task(ss));
//        }

        threadPoolExecutor.submit(()->{
            while (true) {
                try {
                    Thread.sleep(5000);
                    System.out.println();
                    System.out.println("-------------");
                    System.out.println("当前客户端连接数" + (num.get() - 1));
                    System.out.println("-------------");
                    System.out.println();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        while (true){
            if (threadPoolExecutor.getActiveCount()<=num.get()){
                threadPoolExecutor.submit(new Task(ss));
            }
        }


    }



}

任务类


package server;

import bean.User;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import util.JDBCUtils;

import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.Scanner;

public class Task implements Runnable {

    private ServerSocket ss;


    private User query=null;

    private Connection conn = null;

    public Task(ServerSocket ss) {
        this.ss = ss;
    }

    @Override
    public void run() {

        InputStream is=null;

        OutputStream os=null;

        Scanner sc=new Scanner(System.in);

        //绑定客户端
        Socket accept=null;


        try {
             accept = ss.accept();

            Server.num.incrementAndGet();

            System.out.println("accept = " + accept);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("绑定客户端出错");
        }

        //获取客户端信息
        InetAddress inetAddress = accept.getInetAddress();
        String hostName = inetAddress.getHostName();
        String hostAddress = inetAddress.getHostAddress();

        //获取输入流
        try {
             is = accept.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //读取数据
        byte[] bytes=new byte[1024];
        int len = 0;

        //获取登录的用户名
        try {
            len=is.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String name = new String(bytes,0,len);

        //获取登录的密码

        //二次获取输入流
        try {
            is = accept.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }


        try {
            len=is.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String password = new String(bytes,0,len);

        boolean check = check(name, password);

        //写回结果
        try {
           os= accept.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (check){

            try {
                os.write(("登录成功,欢迎"+name+" 你当前IP + "+hostAddress).getBytes());
                //获取客户端发送的消息
                while (true){
                    len=is.read(bytes);
                    String inmessage = new String(bytes, 0, len);

                    if (inmessage.contains("退出")){
                       break;
                    }

                    String now = LocalDateTime.now().toString();
                    System.out.println("收到消息 : "+inmessage+"   @@  用户 "+name+"  消息,请回复!!"+" 当前时间: "+now);

                    System.out.print("回复: " + name + "   :  ");
                        //写回消息
                      String  outmessage = sc.nextLine();

                    os.write(outmessage.getBytes());
                    System.out.println("消息回复成功!!"+" 当前时间: "+now);

                    //保存到服务器
                    saveMessage(query.getId(),inmessage,outmessage,now);
                    System.out.println("聊天记录保存成功!");
                }

                //聊天结束,断开连接
                System.out.println(Thread.currentThread().getName()+"--退出");
                accept.close();
                Server.num.decrementAndGet();
                return;

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.closeSource(conn,null);
            }

        }else {
            try {
                os.write(("登录失败,账户或者密码错误!").getBytes());
                //断开连接,结束线程
                accept.close();
                System.out.println(Thread.currentThread().getName()+"--退出");
                Server.num.decrementAndGet();
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    //判断用户名和密码是否正确
    public boolean check(String name,String password)  {

        System.out.println("select * from user where name = "+name+" and password = "+password);
        //获取连接
         conn = JDBCUtils.getConnection();

        //使用DBUtil
        try {
            query = new QueryRunner().query(
                    conn,
                    "select * from user where name = ? and password = ?",
                    new BeanHandler<User>(User.class),
                    name,
                    password
            );
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("服务端验证账户和密码时出错");
            //关闭资源
            JDBCUtils.closeSource(conn,null);

            return false;
        }
        System.out.println("query = " + query);
        if (query!=null){
            return true;
        }else {
            //关闭资源
            JDBCUtils.closeSource(conn,null);

            return false;
        }
    }

    //保存消息记录
    public void saveMessage(int id,String inMessage,String outMessage,String data){
        try {
            int update = new QueryRunner().update(
                    conn,
                    "insert into chat_history values (null,?,?,?,?)",
                    id,
                    inMessage,
                    outMessage,
                    data
            );

            if (update!=1){
                System.out.println("保存聊天记录出错");
            }


        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("保存聊天记录出错");
        }


    }

}

img

img

img

  • 写回答

1条回答 默认 最新

  • 尘风-随手记 2021-10-28 09:32
    关注

    你那个Server服务端的那句话能打出来是类会先加载静态代码块。先启动的Server吗

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 11月5日
  • 已采纳回答 10月28日
  • 修改了问题 10月27日
  • 创建了问题 10月27日

悬赏问题

  • ¥15 在若依框架下实现人脸识别
  • ¥15 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同