秋日的晚霞 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 求视频摘要youtube和ovp数据集
  • ¥15 怎么改成输入一个要删除的数后现实剩余的数再输入一个删除的数再现实剩余的数用yes表示继续no结束程序
  • ¥15 在启动roslaunch时出现如下问题
  • ¥15 汇编语言实现加减法计算器的功能
  • ¥20 关于多单片机模块化的一些问题
  • ¥30 seata使用出现报错,其他服务找不到seata
  • ¥35 引用csv数据文件(4列1800行),通过高斯-赛德尔法拟合曲线,在选取(每五十点取1点)数据,求该数据点的曲率中心。
  • ¥20 程序只发送0X01,串口助手显示不正确,配置看了没有问题115200-8-1-no,如何解决?
  • ¥15 Google speech command 数据集获取