所以我正在開發一個聊天程序,現在我想添加一個發送文件選項。 我試着添加它,它的工作,但在文件傳輸完成後,兩個套接字關閉(兩個客戶端的套接字)。 下面是聊天客戶端的SSCCE:Java - 通過套接字發送文件(聊天客戶端 - >服務器 - >另一個聊天客戶端)
public class SSCCEChatClient extends JFrame {
private JPanel contentPane;
private JTextField inputUsernameField;
private JTextArea textArea;
String serversock = "84.252.37.82";
String username;
Socket sock;
BufferedReader reader;
PrintWriter writer;
InputStreamReader streamreader;
public class IncomingReader implements Runnable{
public void run() {
String stream;
String[] data;
try {
while ((stream = reader.readLine()) != null) {
data = stream.split("`");
if(data[2].equals("receiveFile")&&(!data[3].equals(username))){
DataInputStream in = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[Integer.parseInt(data[1])];
in.read(bytes);
FileOutputStream fos = new FileOutputStream(System.getProperty("user.home") + "\\Desktop\\" + data[0]);
fos.write(bytes);
fos.close();
in.close();
textArea.append("Success!");
}else if(data[2].equals("server")){
textArea.append(data[0]);
}
}
}catch(Exception ex) {
}
}
}//Incoming Reader
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SSCCEChatClient frame = new SSCCEChatClient();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SSCCEChatClient() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
textArea = new JTextArea();
contentPane.add(textArea, BorderLayout.SOUTH);
JButton btnNewButton = new JButton("Send File");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File transferFile = new File (System.getProperty("user.home") + "\\Desktop\\PNG\\Night.png");
byte [] bytearray = new byte [(int)transferFile.length()];
try {
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(transferFile));
bin.read(bytearray,0,bytearray.length);
DataOutputStream os = new DataOutputStream(sock.getOutputStream());
writer.println(transferFile.getName() + "`" + transferFile.length() + "`receiveFile`" + username);
writer.flush();
os.write(bytearray,0,bytearray.length);
os.flush();
bin.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("File transfer complete");
}
});
contentPane.add(btnNewButton, BorderLayout.CENTER);
JButton btnNewButton_1 = new JButton("Connect");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
username = inputUsernameField.getText();
sock = new Socket(serversock, 5000);
streamreader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamreader);
writer = new PrintWriter(sock.getOutputStream());
Thread IncomingReader = new Thread(new IncomingReader());
IncomingReader.start();
writer.println(username + "``connect");
writer.flush();
} catch (Exception ex) {
textArea.append("\nCannot Connect!");
}
}
});
contentPane.add(btnNewButton_1, BorderLayout.WEST);
inputUsernameField = new JTextField();
contentPane.add(inputUsernameField, BorderLayout.NORTH);
inputUsernameField.setColumns(10);
}
}
這裏是服務器端:
public class SSCCEServer {
static ArrayList<PrintWriter> clientOutputStreams;
static ArrayList<DataOutputStream> clientDataOutputStreams;
static ArrayList<String> onlineUsers = new ArrayList<>();
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket sock;
PrintWriter client;
public ClientHandler(Socket clientSocket, PrintWriter user) {
// new inputStreamReader and then add it to a BufferedReader
client = user;
try {
sock = clientSocket;
System.out.println(clientSocket.getRemoteSocketAddress().toString() + " - ");
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
}
catch (Exception ex) {
System.out.println("error beginning StreamReader");
}
}
public void run() {
String message;
String[] data;
try {
while ((message = reader.readLine()) != null) {
data = message.split("`");
if(data[2].equals("receiveFile")){
DataInputStream in = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[Integer.parseInt(data[1])];
in.read(bytes);
tellEveryone(data[0] + "`" + data[1] + "`" + data[2] + "`" + data[3]);
for(DataOutputStream dos:clientDataOutputStreams){
try {
dos.write(bytes);
dos.close();
}
catch (Exception ex) {
System.out.println("error telling everyone");
}
}
tellEveryone("File transfer complete``server");
}else if(data[2].equals("connect")){
System.out.println(data[0] + "has connected.");
}else {
System.out.println("No Conditions were met.");
}
}
}
catch (Exception ex) {
System.out.println("lost a connection");
System.out.println(ex.getMessage().toString());
clientOutputStreams.remove(client);
}
}
}
public void tellEveryone(String message) {
// sends message to everyone connected to server
for(PrintWriter writer:clientOutputStreams){
try {
writer.println(message);
//pop("Sending: " + message);
writer.flush();
}
catch (Exception ex) {
System.out.println("error telling everyone");
}
}
}
public static void main(String[] args) {
new SSCCEServer().go();
}
public void go(){
clientOutputStreams = new ArrayList<PrintWriter>();
clientDataOutputStreams = new ArrayList<>();
try {
@SuppressWarnings("resource")
ServerSocket serverSock = new ServerSocket(5000);
while(true){
Socket clientSock = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
clientOutputStreams.add(writer);
clientDataOutputStreams.add(new DataOutputStream(clientSock.getOutputStream()));
Thread listener = new Thread(new ClientHandler(clientSock, writer));
listener.start();
}
}
catch (Exception ex)
{
System.out.println("error making a connection");
}
}
}
很抱歉,如果這是真的很長,但這是最小量我可以把它。它也不是全部,因爲它錯過了發送文本方法,但不影響SSCCE。我已經用服務器端的方法'tellEveryone'演示了send方法。 此外,「\ PNG \ Night.png」只是一個例子,您可以創建自己的文件夾和文件以運行SSCCE。 我能做些什麼來修復文件發送後套接字的關閉?
如何使我的代碼更好,請在codereview.SE中。關於套接字關閉,你複製一個更簡潔的問題http://stackoverflow.com/questions/2826311/writing-to-socket-outputstream-w-o-closing-it – Val