使用JAVA SOCKET实现c/s结构的通讯程序,以实现客户端向服务器端的文件的上传以及服务器端向客户端的文件的下载。java
实现思路:服务器
一、在服务器端,建立SocketServer对象,监听某一端口,有链接请求则开一个线程处理这一请求socket
二、在客户端,根据服务器的ip地址以及端口号,建立socket链接,并经过此链接传送数据以及信号this
实现效果:编码
①首先打开服务器程序:.net
②打开客户端程序,输入服务器ip,这里因为都运行在本地,输入127.0.0.1:线程
③客户端启动,显示选择菜单:3d
④选择1注册开始注册,注册结束后在服务器端会添加用户,客户端回到菜单:code
⑤选择2登陆开始使用刚才注册的账号登陆,登陆成功后进入子菜单:server
⑥以上过程在服务器端都有记录:
⑦客户端中在子菜单选择1上传文件,输入要上传的文件的路径(这里使用绝对路径,也可使用相对路径):
⑧客户端上传文件,须要服务器端的赞成:
⑨若不一样意客户端的文件上传,则取消:
⑩客户端也会收到文件没法上传的通知,而且再次进入菜单:
11、再次上传文件,此次服务器端赞成文件上传,则文件会被保存到upload目录下:
12、文件上传成功:
十3、在菜单中选择下载文件,会把服务器端upload文件夹下的文件罗列出来
十4、选择须要下载的文件,下载完成,文件保存在客户端的download文件夹中:
十5、上传下载的文件:
源码以下:
(服务器端程序)
package socket; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; import java.util.Scanner; //用户类 class User { public String username; public String password; public List<String> uploadFiles; // 存储上传过的文件名称 } /** * 服务器端程序 * * @author Charles * */ public class Server { public static final int PORT = 12345;// 监听的端口号 // 帐户列表 public static List<User> userList = new ArrayList<User>(); public static void main(String[] args) { System.out.println("-------------------服务器启动------------------\n"); Server server = new Server(); server.init(); } public void init() { try { ServerSocket serverSocket = new ServerSocket(PORT); while (true) { // 一旦有堵塞, 则表示服务器与客户端得到了链接 Socket client = serverSocket.accept(); // 处理此次链接 new HandlerThread(client); } } catch (Exception e) { System.out.println("服务器异常: " + e.getMessage()); } } // 处理数据传输的线程 private class HandlerThread implements Runnable { private Socket socket; public HandlerThread(Socket client) { socket = client; new Thread(this).start(); System.out.println("调用一次处理线程"); } public void run() { try { // 读取客户端数据的流 DataInputStream input = new DataInputStream(socket.getInputStream()); // 向客户端回复信息的流 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); // 接收客户端的选项 String clientInputStr = input.readUTF(); switch (clientInputStr) { case "申请注册": { String usernamepassword = input.readUTF(); // 获取注册的信息 String[] strs = usernamepassword.split("#"); // 根据上传的注册信息添加用户 User user = new User(); user.username = strs[0]; user.password = strs[1]; user.uploadFiles = new ArrayList<String>(); userList.add(user); System.out.println("成功添加用户:" + user.username); // System.out.println(userList); out.writeUTF("注册成功!"); break; } // #case "申请注册" case "申请登陆": { String usernamepassword = input.readUTF(); // 获取注册的信息 String[] strs = usernamepassword.split("#"); System.out.println("客户端试图登陆的账号:" + strs[0]); boolean canlogin = false; User curuser = null; for (User u : userList) { if (u.username.equals(strs[0]) && u.password.equals(strs[1])) { // 能够登陆 curuser = u; canlogin = true; break; } } if (canlogin) { // 用户名和密码正确 out.writeBoolean(true); // 向客户端返回能够登陆的信号 System.out.println("验证成功,已登陆!\n"); boolean rei = true; // 循环接收传送文件 while (rei) { // 接收到模块编号 clientInputStr = input.readUTF(); switch (clientInputStr) { case "退出文件上传下载模块": { // 退出文件上传下载模块 rei = false; break; } case "申请上传文件": { // 申请上传文件 clientInputStr = input.readUTF(); // 接收文件名 System.out.println("客户端上传的文件的文件名为:" + clientInputStr.substring(1) + " 是否接收此文件?(y/n)"); char receive = new Scanner(System.in).nextLine().toCharArray()[0]; receive = Character.toLowerCase(receive); if (receive == 'y') { out.writeBoolean(true); File f = new File("upload/" + clientInputStr .substring(clientInputStr.lastIndexOf("/") + 1, clientInputStr.length())); if (!f.getParentFile().exists()) { f.getParentFile().mkdir(); } if (!f.exists()) { f.createNewFile(); } FileOutputStream fos = new FileOutputStream(f); byte[] buffer = new byte[1024]; int flag = -1; System.out.print("接收文件中..."); // 构造结束标志 byte[] endstr = "文件上传结束".getBytes("utf-8"); byte[] sendend = new byte[1024]; for (int i = 0; i < endstr.length; i++) { sendend[i] = endstr[i]; } // 当未读取到结束标志的时候就一直读取 while ((flag = input.read(buffer)) != -1 && !new String(buffer, "utf-8").equals(new String(sendend, "utf-8"))) { fos.write(buffer); buffer = new byte[1024]; } fos.close(); System.out.println("\n文件上传结束!\n"); } else { System.out.println("已经拒绝客户端的服务器上传!"); out.writeBoolean(false); } continue; } case "申请下载文件": { // 申请下载文件 // 首先获取全部upload目录下的文件 File uploadDir = new File("upload"); if (uploadDir.exists()) { // 存在该目录 out.writeBoolean(true); // 获取目录下全部文件 File[] files = uploadDir.listFiles(); String hint = "服务器上一共有" + files.length + "个文件\n0、退出下载\n"; for (int i = 0; i < files.length; i++) { hint += (i+1)+"、"+files[i].getName()+"\n"; } hint += "请输入须要下载的文件序号:"; out.writeUTF(hint); int fileId=input.readInt(); if(fileId==0) { continue; } out.writeUTF(files[fileId-1].getName()); // 构造结束标志 byte[] endstr = "文件下载结束".getBytes("utf-8"); byte[] sendend = new byte[1024]; for (int i = 0; i < endstr.length; i++) { sendend[i] = endstr[i]; } //获取文件输入流 FileInputStream fin = new FileInputStream(files[fileId-1]); byte[] buffer = new byte[1024]; int readflag=-1; System.out.println("正在向客户端发送文件..."); while((readflag=fin.read(buffer))!=-1) { out.write(buffer); } fin.close(); out.write(sendend); System.out.println("文件发送成功!\n"); continue; } else { // 目录不存在,说明没法下载 out.writeBoolean(false); } continue; } default: { break; } } } } else { out.writeBoolean(false); // 向客户端返回不能登陆的信号 System.out.println("验证失败不容许登陆!\n"); } } // #case "申请登陆" }// #switch // 关闭流 out.close(); input.close(); } catch (Exception e) { //e.printStackTrace(); System.out.println("服务器 run 异常: " + e.getMessage()); } finally { if (socket != null) { try { socket.close(); } catch (Exception e) { //e.printStackTrace(); socket = null; System.out.println("服务端 finally 异常:" + e.getMessage()); } } } } } }
(2)客户端程序
package socket; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.util.Scanner; public class Client { public static String IP_ADDR = "localhost";// 服务器地址 public static final int PORT = 12345;// 服务器端口号 public static void main(String[] args) { System.out.print("请输入要链接的服务器IP地址:"); Scanner in = new Scanner(System.in); IP_ADDR = in.next(); // 获取服务器地址 System.out.println("\n------------------客户端启动--------------------\n"); boolean f1 = true; // 是否退出的标志变量 while (f1) { System.out.print("菜单:\n一、注册\n二、登陆\n三、退出\n请输入你的选择序号:"); int select = in.nextInt(); switch (select) { case 1: { // 注册 Socket socket = null; try { System.out.println("------------------开始注册--------------------"); System.out.println("请输入用户名(不得包含\"#\"):"); String username = in.next(); if (username.contains("#")) { // 检查用户名是否合法 System.out.println("用户名不合法"); continue; // 跳出本次循环继续 } System.out.println("请输入密码(不得包含\"#\"):"); String password = in.next(); if (password.contains("#")) { // 检查密码是否合法 System.out.println("密码不合法"); continue; // 跳出本次循环继续 } // 建立一个流套接字并将其链接到指定主机上的指定端口号 socket = new Socket(IP_ADDR, PORT); // 向服务器传递数据的流 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); // 读取服务器端数据的流 DataInputStream input = new DataInputStream(socket.getInputStream()); out.writeUTF("申请注册"); String usernamepassword = username + "#" + password; out.writeUTF(usernamepassword); // 传送注册信息 String msg = input.readUTF(); System.out.println("服务器端:" + msg + "\n"); } catch (IOException e) { System.out.println("客户端注册异常:" + e.getMessage()); } finally { // 关闭socket链接,释放资源 if (socket != null) { try { socket.close(); } catch (IOException e) { socket = null; e.printStackTrace(); System.out.println("客户端 finally 异常:" + e.getMessage()); } } } break; } case 2: { // 登陆 Socket socket = null; try { System.out.println("\n------------------开始登陆--------------------"); System.out.println("请输入用户名:"); String username = in.next(); System.out.println("请输入密码:"); String password = in.next(); String usernamepassword = username + "#" + password; // 建立一个流套接字并将其链接到指定主机上的指定端口号 socket = new Socket(IP_ADDR, PORT); // 向服务器传递数据的流 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); // 读取服务器端数据的流 DataInputStream input = new DataInputStream(socket.getInputStream()); out.writeUTF("申请登陆"); // 向服务器提交登陆的请求,等待服务器响应 out.writeUTF(usernamepassword); // 向服务器上传登陆信息以验证 boolean msg = input.readBoolean(); // 读取服务器响应的信号,判断是否能够登陆 if (msg) { // 登录成功 System.out.println("登陆验证成功!\n"); // 开始进入上传下载文件模块 boolean f = true; while (f) { System.out.print("菜单:\n一、上传文件\n二、下载文件\n三、退出\n请输入你的选择序号:"); int choice = in.nextInt(); switch (choice) { case 1: { // 上传文件 try { out.writeUTF("申请上传文件"); // 向服务器提出上传文件的申请 // 向服务器端上传文件 System.out.println("\n请输入要上传的文件的路径(绝对路径或者相对于应用程序的相对路径):"); String uploadFileName = in.next(); // 先把文件名传给服务器 out.writeUTF("/" + uploadFileName); System.out.println("等待服务器确认接收文件..."); boolean ret = input.readBoolean(); // 以utf编码读取 if (!ret) { System.out.println("服务器端拒绝接收此文件!"); continue; } else { BufferedInputStream fin = new BufferedInputStream( new FileInputStream(new File(uploadFileName))); byte[] buffer = new byte[1024]; int flag = -1; System.out.print("上传文件中..."); while ((flag = fin.read(buffer)) != -1) { // 当未读取结束的时候就一直读取而且发送 out.write(buffer); } fin.close(); System.out.println("\n上传结束!\n"); } // out.close(); //不能这样写由于会把socket也关闭 // socket.shutdownOutput(); //关闭输出流而不关闭socket ,最后发现也不能这样,由于output没法再次打开 // 构造结束标志 byte[] endstr = "文件上传结束".getBytes("utf-8"); byte[] sendend = new byte[1024]; for (int i = 0; i < endstr.length; i++) { sendend[i] = endstr[i]; } out.write(sendend); } catch (Exception e) { e.printStackTrace(); System.out.println("客户端异常:" + e.getMessage()); } finally { continue; } } case 2: { // 下载文件 out.writeUTF("申请下载文件"); // 向服务器提出下载文件的申请 boolean candown = input.readBoolean(); if (candown) { System.out.println(input.readUTF()); int fileId = in.nextInt(); if (fileId == 0) { out.writeInt(0); continue; } else { out.writeInt(fileId); // 获取文件名 String fname = input.readUTF(); // 接收文件 File df = new File("download/" + fname); if (!df.getParentFile().exists()) { df.getParentFile().mkdir(); } if (!df.exists()) { df.createNewFile(); } FileOutputStream fos = new FileOutputStream(df); byte[] buffer = new byte[1024]; int flag = -1; System.out.print("下载文件中..."); // 构造结束标志 byte[] endstr = "文件下载结束".getBytes("utf-8"); byte[] sendend = new byte[1024]; for (int i = 0; i < endstr.length; i++) { sendend[i] = endstr[i]; } // 当未读取到结束标志的时候就一直读取 while ((flag = input.read(buffer)) != -1 && !new String(buffer, "utf-8").equals(new String(sendend, "utf-8"))) { fos.write(buffer); buffer = new byte[1024]; } fos.close(); System.out.println("文件下载结束!\n"); continue; } } else { System.out.println("服务器上暂无文件能够下载!"); continue; } } case 3: { // 退出上传下载 out.close(); input.close(); f = false; System.out.println("客户端已退出文件上传下载模块。"); break; } default: { out.close(); input.close(); break; } } } } else { // 登陆失败 System.out.println("登陆验证失败!\n"); if (socket != null) { try { socket.close(); } catch (IOException e) { socket = null; //e.printStackTrace(); System.out.println("客户端 finally 异常:" + e.getMessage()); } } continue; } } catch (IOException e) { System.out.println("客户端登陆异常:" + e.getMessage()); } finally { break; } } case 3: { System.out.println("--------------------关闭客户端--------------------"); f1 = false; break; } default: { break; } } } } }