关于tcp套接字得到输入输出流的问题

时间:2022-12-10 11:04:27
刚学到java网络编程,想用tcp做一个类似ftp文件传输的东西。结果发现建立了tcp连接却只能传输一次。再次传输的时候提示 Socket is closed。让我很纠结~~查了半天百度,貌似是socket的getInputStream()得到的流被关闭了导致的~~各位大大有什么解决办法~~
代码如下:
server端


import java.io.*;
import java.net.*;

public class Server implements Runnable{
ServerSocket ser = null;
int port = 6666;
BufferedReader br = null;
BufferedWriter bw = null;
Socket soc = null;
File file_send = null;
File file_receive = null;
InputStream ips = null;
OutputStream ops = null;

public void StartServer() {

try {

ser = new ServerSocket(port);
while (true) {
soc = ser.accept();
System.out.println("链接已建立!");
//Thread thread = new Thread(this);
//thread.start();
}
} catch (IOException e) {
System.out.println("ServerSocket创建失败!检查端口是否被占用");
e.printStackTrace();
}

}


////////////////接收////////////////
public void receive() {

try {
ips = soc.getInputStream();
file_receive = new File("D:/hello.java");
br = new BufferedReader(new InputStreamReader(ips));
bw = new BufferedWriter(new FileWriter(file_receive));

String s = null;
while ((s = br.readLine()) != null) {
bw.write(s);
bw.newLine();

}
bw.flush();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("文件接收已完成!");
}
/////////////////////发送/////////////////////////
public void send(){

try {
ops = soc.getOutputStream();
file_send = new File("D:/dos命令参数.txt");
bw = new BufferedWriter(new OutputStreamWriter(ops));
br = new BufferedReader(new FileReader(file_send));
String s = null;
while((s = br.readLine()) != null){
bw.write(s,0,s.length());
bw.newLine();
}
System.out.println("文件发送已完成!");
bw.flush();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}


@Override
public void run() {
send();
receive();

}


}

client端

package com.yao;

import java.io.*;
import java.net.*;

public class Client {
public int port = 6666;
public String host = "127.0.0.1";
Socket soc = null;
File file_receive = null;
File file_send = null;
BufferedReader br = null;
BufferedWriter bw = null;
OutputStream ops = null;
InputStream ips = null;

/////////////建立连接/////////////
public void Connect(){
try {
soc = new Socket(host,port);
} catch (UnknownHostException e) {
System.out.println("无法在主机号:"+host+"创建监听!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("无法在端口"+port+"添加监听");
e.printStackTrace();
}
}

////////////////发送/////////////////////////
public void send(){
try {
ops = soc.getOutputStream();
file_send = new File("D:/Hello.txt");
br = new BufferedReader(new FileReader(file_send));
bw = new BufferedWriter(new OutputStreamWriter(ops));
String s = null;
while((s = br.readLine()) != null){
bw.write(s,0,s.length());
bw.newLine();
}
System.out.println("文件发送已完成!");
bw.flush();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}


/////////////////////接收/////////////////////
public void receive() {

try {
ips = soc.getInputStream();
file_receive = new File("D:/dos命令参数.java");
br = new BufferedReader(new InputStreamReader(ips));
bw = new BufferedWriter(new FileWriter(file_receive));

String s = null;
while ((s = br.readLine()) != null) {
bw.write(s);
bw.newLine();

}
bw.flush();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("文件接收已完成!");
}

}

9 个解决方案

#1


因为你在发送文件的时候,直接把bw给关闭了,这样导致socket关闭,然后在接收的时候就会出现问题,而且你的server和client都不严谨,server程序很明显在并发的时候会出错,线程不能这样些,顺便附上我简单修改过的,表达能力不行,希望你能理解

Server

package server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

private int port;
Server(int port) {
this.port = port;
}

    public void StartServer() {
        try {
         ServerSocket server = new ServerSocket(port);
            while (true) {
             try{
             new Thread(new ServerProcess(server.accept())).start();
             }catch(Exception ex){
             ex.printStackTrace();
             }
            }
        } catch (IOException e) {
            System.out.println("ServerSocket创建失败!检查端口"+port+"是否被占用");
            e.printStackTrace();
        }

    }
}

class ServerProcess implements Runnable{

private static final String SEND_PATH = "D:/dos命令参数.txt";    //发送文件路径
private static final String RECV_PATH = "D:/hello.java"; //接收文件路径

    private InputStream in;
    private OutputStream out;
    
ServerProcess(Socket socket) {
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("socket 错误!");
}
}
    ////////////////接收////////////////
    private void receive() {
     FileOutputStream fileOut = null;
        try {
            File file_receive = new File(RECV_PATH);
            fileOut = new FileOutputStream(file_receive);
            pipe(fileOut,in);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
         if(null != fileOut){
         try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
         }
        }
        System.out.println("文件接收已完成!");
    }
    
private void pipe(OutputStream out,InputStream in) throws IOException {
byte[] buf = new byte[512];
int len = 0;
while((len = in.read(buf)) != -1) {
out.write(buf,0,len);
}
}
/////////////////////发送/////////////////////////
    private void send(){
        FileInputStream fileIn = null;
        try {
            File file_send = new File(SEND_PATH);
            fileIn = new FileInputStream(file_send);
            pipe(out,fileIn);
            System.out.println("文件发送已完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
         if(null != fileIn) {
         try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
         }
        }
    }
    @Override
    public void run() {
     try{
     send();
        receive();
     }finally{
     try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
     }
    }
}


Server启动代码 new Server(6666).StartServer();

Client

package client;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
private static final String SEND_PATH = "D:/dos命令参数1.txt";
private static final String RECV_PATH = "D:/hello1.java";

private InputStream in;
private OutputStream out;

Client(String host, int port) {
try {
Socket socket = new Socket(host, port);
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (UnknownHostException e) {
System.out.println("无法找到主机:" + host);
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
System.out.println("可能是端口错误 :" + port);
e.printStackTrace();
throw new RuntimeException(e);
}
}

// //////////////发送/////////////////////////
private void send() {
InputStream fileIn = null;
try {
fileIn = new FileInputStream(SEND_PATH);
pipe(out, fileIn);
System.out.println("文件发送完成");
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != fileIn) {
try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

// ///////////////////接收/////////////////////
private void receive() {
OutputStream fileOut = null;
try {
fileOut = new FileOutputStream(RECV_PATH);
pipe(fileOut,in);
System.out.println("文件接收已完成!");
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != fileOut){
try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

private void pipe(OutputStream out, InputStream in) throws IOException {
byte[] buf = new byte[512];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}

public void run() {
try{
send();
receive();
}finally{
try{
in.close();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

}

Client启动代码
new Client("127.0.0.1",6666).run();

最后还有一个小小的建议,发送和接受文件不要弄成同一个,比较容易出错

#2


你的代码中只能读入1个文件, 传送,然后写入一个文件。并不支持多个文件的读入,和多个文件的写入。
你只要在Server中结束一个文件时,重新new出所有流(包括一个新文件)
在客户端中,写完第一个文件时,重新建立所有流(包括一个新输入文件),所有的socket不要动,还用原来的,也不要释放就可以。

#3


别管怎么说 先谢谢你们两位了~~
第一次写tcp的东西,自己确实不怎么会~~东拼西凑了这么个东西,我自己再改改,谢谢两位的回答

#4


我的代码给你参考:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.swing.JLabel;
import javax.swing.JTextArea;


public class GetMessage extends Thread{
private int i;
String v;

JLabel label=null;
private JTextArea text;
Date d=new Date();
SimpleDateFormat matter=new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
public GetMessage(int i,JTextArea text) {

this.i=i;
this.text=text;
}

public void run(){
try {
ServerSocket so = new ServerSocket(i);
Socket s = so.accept();
while(true){
InputStreamReader i = new InputStreamReader(s.getInputStream());
BufferedReader b = new BufferedReader(i);
 v= b.readLine();
  text.append(String.valueOf(matter.format(d))+"\n");
   text.append("对方说"+v+"\n");
 }
} catch (IOException e) {
System.out.println(e.getMessage());
//label.setText("对方已经下线");
text.append("对方下线了。。。");
}
}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;


public class SendMessage extends Thread {
private String ip;
private int i;
Socket s = null;
JLabel label=null;
JTextField text;
JTextArea text1;

public SendMessage(String ip,int i,JTextArea text1) {
// TODO Auto-generated constructor stub
this.ip=ip;
this.i=i;
this.text1=text1;
  
}


    public void run(){
    
     while(true){
try {
 s = new Socket(ip,i);
     text1.setText("连接成功"+"\n");
 break;
} catch (Exception e) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
System.out.println("出错了。。。。");
}

     }
    
    }                        
    
     public  void send(String message)
     {
try {



PrintStream p = new PrintStream(s.getOutputStream());

p.println(message);

    
} catch (Exception e1) {
System.out.println("异常"+e1.getMessage());
}
}
      
      
}

#5


恩  你这个聊天软件也不错哈  头回发提问帖,谢谢各位好心人的回复
这会仔细读了下二楼的代码~~~哥们谦虚了,很严谨的程序,受教了。
我还想知道的是为什么我关闭bw的时候会关闭 socket而二楼的代码却不会?领悟能力有限,哪位好心人给解答下~ 关于tcp套接字得到输入输出流的问题

#6


额,上一个问题二了~~~~二楼的代码没有关闭过 in和 out,只在最后文件传输完毕后关闭了这两个流。如果想在in和out上再包上其它的高层流该,比如说BufferedReader,BufferedWriter啥的,怎么处理?也不关闭么?会不会存在什么问题?

#7


用多线程试一下

#8


引用 6 楼 dnfpyz2012 的回复:
额,上一个问题二了~~~~二楼的代码没有关闭过 in和 out,只在最后文件传输完毕后关闭了这两个流。如果想在in和out上再包上其它的高层流该,比如说BufferedReader,BufferedWriter啥的,怎么处理?也不关闭么?会不会存在什么问题?

对于socket编成
1、client连上后,如果是同步短连接的话,数据传输完后需要关闭is和os,同时关闭socket。
2、如果是长连接的话,就什么都不要关。
3、你用BufferedReader,BufferedWriter最终都是调用了socket相关的inputstream和outputStream,BufferedReader,BufferedWriter只是对这两个流进行包装,最终数据传输完成,还是要参照1、2

#9


你在调用 BufferedReader,BufferedWriter的close方法,方法内部什么自己调用被 包装类的close方法,所以你只需要显示的调用 BufferedReader,BufferedWriter的close方法即可

#1


因为你在发送文件的时候,直接把bw给关闭了,这样导致socket关闭,然后在接收的时候就会出现问题,而且你的server和client都不严谨,server程序很明显在并发的时候会出错,线程不能这样些,顺便附上我简单修改过的,表达能力不行,希望你能理解

Server

package server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

private int port;
Server(int port) {
this.port = port;
}

    public void StartServer() {
        try {
         ServerSocket server = new ServerSocket(port);
            while (true) {
             try{
             new Thread(new ServerProcess(server.accept())).start();
             }catch(Exception ex){
             ex.printStackTrace();
             }
            }
        } catch (IOException e) {
            System.out.println("ServerSocket创建失败!检查端口"+port+"是否被占用");
            e.printStackTrace();
        }

    }
}

class ServerProcess implements Runnable{

private static final String SEND_PATH = "D:/dos命令参数.txt";    //发送文件路径
private static final String RECV_PATH = "D:/hello.java"; //接收文件路径

    private InputStream in;
    private OutputStream out;
    
ServerProcess(Socket socket) {
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("socket 错误!");
}
}
    ////////////////接收////////////////
    private void receive() {
     FileOutputStream fileOut = null;
        try {
            File file_receive = new File(RECV_PATH);
            fileOut = new FileOutputStream(file_receive);
            pipe(fileOut,in);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
         if(null != fileOut){
         try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
         }
        }
        System.out.println("文件接收已完成!");
    }
    
private void pipe(OutputStream out,InputStream in) throws IOException {
byte[] buf = new byte[512];
int len = 0;
while((len = in.read(buf)) != -1) {
out.write(buf,0,len);
}
}
/////////////////////发送/////////////////////////
    private void send(){
        FileInputStream fileIn = null;
        try {
            File file_send = new File(SEND_PATH);
            fileIn = new FileInputStream(file_send);
            pipe(out,fileIn);
            System.out.println("文件发送已完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
         if(null != fileIn) {
         try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
         }
        }
    }
    @Override
    public void run() {
     try{
     send();
        receive();
     }finally{
     try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
     }
    }
}


Server启动代码 new Server(6666).StartServer();

Client

package client;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
private static final String SEND_PATH = "D:/dos命令参数1.txt";
private static final String RECV_PATH = "D:/hello1.java";

private InputStream in;
private OutputStream out;

Client(String host, int port) {
try {
Socket socket = new Socket(host, port);
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (UnknownHostException e) {
System.out.println("无法找到主机:" + host);
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
System.out.println("可能是端口错误 :" + port);
e.printStackTrace();
throw new RuntimeException(e);
}
}

// //////////////发送/////////////////////////
private void send() {
InputStream fileIn = null;
try {
fileIn = new FileInputStream(SEND_PATH);
pipe(out, fileIn);
System.out.println("文件发送完成");
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != fileIn) {
try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

// ///////////////////接收/////////////////////
private void receive() {
OutputStream fileOut = null;
try {
fileOut = new FileOutputStream(RECV_PATH);
pipe(fileOut,in);
System.out.println("文件接收已完成!");
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != fileOut){
try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

private void pipe(OutputStream out, InputStream in) throws IOException {
byte[] buf = new byte[512];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}

public void run() {
try{
send();
receive();
}finally{
try{
in.close();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

}

Client启动代码
new Client("127.0.0.1",6666).run();

最后还有一个小小的建议,发送和接受文件不要弄成同一个,比较容易出错

#2


你的代码中只能读入1个文件, 传送,然后写入一个文件。并不支持多个文件的读入,和多个文件的写入。
你只要在Server中结束一个文件时,重新new出所有流(包括一个新文件)
在客户端中,写完第一个文件时,重新建立所有流(包括一个新输入文件),所有的socket不要动,还用原来的,也不要释放就可以。

#3


别管怎么说 先谢谢你们两位了~~
第一次写tcp的东西,自己确实不怎么会~~东拼西凑了这么个东西,我自己再改改,谢谢两位的回答

#4


我的代码给你参考:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.swing.JLabel;
import javax.swing.JTextArea;


public class GetMessage extends Thread{
private int i;
String v;

JLabel label=null;
private JTextArea text;
Date d=new Date();
SimpleDateFormat matter=new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
public GetMessage(int i,JTextArea text) {

this.i=i;
this.text=text;
}

public void run(){
try {
ServerSocket so = new ServerSocket(i);
Socket s = so.accept();
while(true){
InputStreamReader i = new InputStreamReader(s.getInputStream());
BufferedReader b = new BufferedReader(i);
 v= b.readLine();
  text.append(String.valueOf(matter.format(d))+"\n");
   text.append("对方说"+v+"\n");
 }
} catch (IOException e) {
System.out.println(e.getMessage());
//label.setText("对方已经下线");
text.append("对方下线了。。。");
}
}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;


public class SendMessage extends Thread {
private String ip;
private int i;
Socket s = null;
JLabel label=null;
JTextField text;
JTextArea text1;

public SendMessage(String ip,int i,JTextArea text1) {
// TODO Auto-generated constructor stub
this.ip=ip;
this.i=i;
this.text1=text1;
  
}


    public void run(){
    
     while(true){
try {
 s = new Socket(ip,i);
     text1.setText("连接成功"+"\n");
 break;
} catch (Exception e) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
System.out.println("出错了。。。。");
}

     }
    
    }                        
    
     public  void send(String message)
     {
try {



PrintStream p = new PrintStream(s.getOutputStream());

p.println(message);

    
} catch (Exception e1) {
System.out.println("异常"+e1.getMessage());
}
}
      
      
}

#5


恩  你这个聊天软件也不错哈  头回发提问帖,谢谢各位好心人的回复
这会仔细读了下二楼的代码~~~哥们谦虚了,很严谨的程序,受教了。
我还想知道的是为什么我关闭bw的时候会关闭 socket而二楼的代码却不会?领悟能力有限,哪位好心人给解答下~ 关于tcp套接字得到输入输出流的问题

#6


额,上一个问题二了~~~~二楼的代码没有关闭过 in和 out,只在最后文件传输完毕后关闭了这两个流。如果想在in和out上再包上其它的高层流该,比如说BufferedReader,BufferedWriter啥的,怎么处理?也不关闭么?会不会存在什么问题?

#7


用多线程试一下

#8


引用 6 楼 dnfpyz2012 的回复:
额,上一个问题二了~~~~二楼的代码没有关闭过 in和 out,只在最后文件传输完毕后关闭了这两个流。如果想在in和out上再包上其它的高层流该,比如说BufferedReader,BufferedWriter啥的,怎么处理?也不关闭么?会不会存在什么问题?

对于socket编成
1、client连上后,如果是同步短连接的话,数据传输完后需要关闭is和os,同时关闭socket。
2、如果是长连接的话,就什么都不要关。
3、你用BufferedReader,BufferedWriter最终都是调用了socket相关的inputstream和outputStream,BufferedReader,BufferedWriter只是对这两个流进行包装,最终数据传输完成,还是要参照1、2

#9


你在调用 BufferedReader,BufferedWriter的close方法,方法内部什么自己调用被 包装类的close方法,所以你只需要显示的调用 BufferedReader,BufferedWriter的close方法即可