Java使用Socket时遇到的问题的记录

1.代码的书写逻辑

client:

*       1.创建Socket对象并连接服务器
*       2.写出数据
*       3.关闭释放

server:

*   1.创建对象绑定端口
*   2.等待客户端连接
*   3.读取数据
*   4.释放资源

2.返回读取完成标志socket.shutdownOutput(),否则程序将停留在read方法中死等,一直等待读取下面的数据。

// read方法从连接通道读取数据
// 但是,循环需要一个结束标志才能在这里停止
// 否则,程序将停留在read方法中,等待读取下面的数据

3.传输图片时,收到的图片显示不全,查看大小也和发送方的图片大小不一致,导致图片底部失真是因为读写的文件内容大小不一致导致的。错误是出在服务器端程序没有注意读写的同步,BufferedOutpuStream是高级流,数据必须刷新才能冲到另一端,执行socket.shutdownOutputStream()时服务器端已发送数据完毕,但shutdownOutputStream()作用仅仅是关闭当前Socket端的输出流并不会让数据冲到Socket另一端中。   

方法:在数组读取时,在socket.shutdownOutputStream()前,执行bos.flush(),强行将数据冲到客户端中执行bos.flush(),强行将数据冲到客户端中。 

 

详情:关于Socket通信传输图片底部失真问题_shutdownoutstream_paul亡命天涯的博客-CSDN博客

4.随机生成文件名

String name=UUID.randomUUID().toString().replace("-","");//随机生成文件名

5.实现多客户端时,可将服务端实现代码放进循环,但是只用循环的话,必须要等待前一个线程结束才能进行后一个线程。

        while (true) {
            Socket socket=ss.accept();
            String name=UUID.randomUUID().toString().replace("-","");//随机生成文件名
            BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());

            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("C:\\\\Users\\\\WZY\\\\Desktop\\\\"+name+".png"));

            byte[] bytes=new byte[1024];
            int len;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }

            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("上传成功!");
            bw.newLine();
            bw.flush();

            bw.close();
            bos.close();
            socket.close();
            ss.close();
        }

 

 利用多线程实现多客户端

package Excise5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
//只用循环的话,必须要等待前一个线程结束才能进行后一个线程
public class server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss=new ServerSocket(10005);

        while (true) {
            Socket socket=ss.accept();

            new Thread(new MyRunnable(socket)).start();
        }

    }
}
package Excise5;

import java.io.*;
import java.net.Socket;
import java.util.UUID;

//注:直接调用Thread类或Runnable类对象的run()方法是无法启动线程的,这只是一个简单的方法调用必须通过Thread方法中的start()才行。
//创建线程的另一种方法是实现Runnable接口
//必须通过Thread实例才能创建并运行线程。
public class MyRunnable implements  Runnable{
    private Socket socket;
    MyRunnable(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            String name= UUID.randomUUID().toString().replace("-","");//随机生成文件名

            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("C:\\\\Users\\\\WZY\\\\Desktop\\\\"+name+".png"));

            byte[] bytes=new byte[1024];
            int len;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }

            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("上传成功!");
            bw.newLine();
            bw.flush();

            bw.close();
            bos.close();

            //ss.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

        }
    }
}

6.利用线程池可以让结构简洁

        //线程池
        ThreadPoolExecutor pool=new ThreadPoolExecutor(
                3,//核心线程数量
                16,//线程池大小
                60,//空闲时间
                TimeUnit.SECONDS,//空闲时间单位
                new ArrayBlockingQueue<>(2),//队列
                Executors.defaultThreadFactory(),//线程工厂,让线程池创建线程对象
                new ThreadPoolExecutor.AbortPolicy()//阻塞队列
        );

调用线程池的方法去启动新线程

pool.submit(new MyRunnable(socket));

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值