这是一篇关于socket TCP传输的一个完整案例,出于兴趣临时用控制台模拟了一个用户的登陆 注册与文件传输
socket传输的简单模型图如下
在完成这个案例之前出现了几个值得关注的问题
问题1:文件流不能被序列化 怎么将文件 文件的名字.....等等需要传递的数据从客户端传输给服务器端
问题2:怎么解决一个服务器多个客户端的问题
问题3:为什么服务器端只能接收一次客户端的请求,(服务器端与客户端不能连续的交互)
问题4:怎么判断客户端已经断开连接
问题5::服务器端的socket与客户端的socket应该何时去关闭
答案全在代码里边,由于只是做了一个demo 没有将代码封装到极致,有兴趣的小伙伴可以把代码抽离出来进行具体的封装 废话不多说 直接上代码哈
两个实体对象 分别是文件对象与用户对象
package com.javase.socket.obj; import java.io.Serializable; public class SocketUser implements Serializable { /** * 序列化标识 */ private static final long serialVersionUID = 1L; //用户名 private String username; //用户密码 private String password; //逻辑删除标识 private Integer isDelete; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getIsDelete() { return isDelete; } public void setIsDelete(Integer isDelete) { this.isDelete = isDelete; } } package com.javase.socket.obj; import java.io.File; import java.io.Serializable; public class SocketFile implements Serializable{ /** * 序列化标识 */ private static final long serialVersionUID = 1L; /** *文件的名字 */ private String fileName; /** *文件的标识 */ private String fileId; /** *文件的路径 */ private String filePath; /** *客户端的文件 */ private File file; public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getFileId() { return fileId; } public void setFileId(String fileId) { this.fileId = fileId; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } }
socket 服务端代码
package com.javase.socket.obj;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class SocketFileServer extends Thread {
// 定义socket 连接对象
private Socket socket = null;
// 定义字节输入流
private ObjectInputStream in = null;
// 定义自己输出
private ObjectOutputStream out = null;
// 打印流对象
// 定义字符输入缓冲流
// 定义自负输入缓冲流
public SocketFileServer() {
}
public SocketFileServer(Socket socket) {
this.socket = socket;
}
@SuppressWarnings("unchecked")
@Override
public void run() {
boolean done = true;
//while循环会一直等待客户端的请求信息 如果客户端断开连接 则退出
while(done){
try {
//如果抛出异常代表客户端已经断开连接
socket.sendUrgentData(0);
} catch (IOException e1) {
done = false;
e1.printStackTrace();
throw new RuntimeException("客户端已经断开连接..............");
}
Map<String,Object> mapReceive = new HashMap<String,Object>();
try {
// 通过socket 获取字节输入流
in = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
//读取一个map对象
mapReceive = (Map<String, Object>) in.readObject();
if(null != mapReceive){
Integer flag = Integer.parseInt(mapReceive.get("flag")+"");
System.out.println("服务器接收的服务标志为flag=="+flag);
switch (flag) {
case 1:
login(mapReceive);
break;
case 2:
break;
case 3:
fileTransfers(mapReceive);
break;
default:
break;
}
}else{
throw new RuntimeException("服务器接收的数据为null");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*模拟用户的登陆
*@param Map<String,Object> mapReceive 接收客户端传递的map对象
*/
public void login(Map<String,Object> mapReceive) throws IOException{
Map<String,Object> mapSend = new HashMap<String,Object>();
SocketUser user = null;
SocketUser userSend= null;
user = (SocketUser) mapReceive.get("user");
if("xiaobai".equals(user.getUsername()) && "123456".equals(user.getPassword())){
userSend = new SocketUser();
userSend.setPassword("123456");
userSend.setUsername("xupengfei");
}
mapSend.put("user", userSend);
//响应客户端
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(mapSend);
out.flush();
}
public void reg(){
System.out.println("sorry 注册暂未编写 但不影响程序运行.....");
}
/**
* 文件的传输服务
* @param Map<String,Object> mapReceive 接收客户端传递的map对象
*/
public void fileTransfers(Map<String,Object> mapReceive) throws IOException{
Map<String,Object> mapSend = new HashMap<String,Object>();
FileOutputStream fileOut = null;
FileInputStream fileInputStream = null;
SocketFile inOutb =(SocketFile) mapReceive.get("file");
if(null != inOutb){
//先讲客户端传过来的文件传入upload 文件夹
String fileName =inOutb.getFileName();
fileOut = new FileOutputStream("d:\\upload\\"+fileName);
fileInputStream = new FileInputStream(inOutb.getFile());
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
fileOut.write(buf);
fileOut.close();
fileInputStream.close();
//响应客户端
mapSend.put("flag", 1);
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(mapSend);
out.flush();
}
}
public static void main(String[] args) {
try {
//创建一个serverSocket 连接对象
ServerSocket serverSocket = new ServerSocket(8090);
SocketFileServer threadSocket = null;
Socket socket = null;
System.out.println("服务器已经启动........");
while(true){
//接收客户端请求
socket = serverSocket.accept();
threadSocket = new SocketFileServer(socket);
//设置线程的优先级 一定要设置(会影响服务器端与客户端的传输速度)
threadSocket.setPriority(4);
threadSocket.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
socket 客户端代码
package com.javase.socket.obj;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class SocketFileClient extends Thread{
// 定义socket 连接对象
private Socket socket = null;
// 定义对象输入流
private ObjectInputStream in = null;
// 定义对象输出流
private ObjectOutputStream out = null;
private Scanner scanner = null;
private SocketUser user = null;
public SocketFileClient() {
}
public SocketFileClient(Socket socket) {
this.socket = socket;
}
public void run() {
scanner = new Scanner(System.in);
System.out.println("**************请选择服务项目:************");
System.out.println("用户登录:请输入【1】");
System.out.println("用户注册:请输入【2】");
System.out.println("传输文件:请输入【3】");
String serviceFlag = null;
//选择服务项目的标识
serviceFlag = scanner.next();
//判断是否是整数
boolean result=serviceFlag.matches("[0-9]+");
while(!result){
System.out.println("请输入一个整数...");
serviceFlag = scanner.next();
result=serviceFlag.matches("[0-9]+");
}
int flag = Integer.parseInt(serviceFlag);
switch (flag) {
case 1:
try {
login();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
break;
case 2:
regis();
break;
case 3:
try {
fileTransfers();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
break;
}
}
/**
* 用户登录
* @throws IOException
* @throws ClassNotFoundException
* */
@SuppressWarnings("unchecked")
public void login() throws IOException, ClassNotFoundException {
Map<String,Object> mapSend = new HashMap<String,Object>();
Map<String,Object> mapReceive = new HashMap<String,Object>();
SocketUser socketUser = new SocketUser();
System.out.print("请输入用户名:");
String username = scanner.next();
System.out.println();
System.out.print("请输入密码:");
String password = scanner.next();
socketUser.setUsername(username);
socketUser.setPassword(password);
mapSend.put("user", socketUser);
mapSend.put("flag", 1);
// 获取输出流
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(mapSend);
out.flush();
//接收服务器响应
in = new ObjectInputStream(socket.getInputStream());
mapReceive = (Map<String, Object>) in.readObject();
if(null != mapReceive){
user = (SocketUser)mapReceive.get("user");
if(null != user &&!"".equals(user)){
System.out.println( "登陆成功........");
fileTransfers();
}else{
System.out.println("您输出的用户名密码有误,返回主菜单请输入【exit】,重新登陆请按任意键........");
String tempFlag = scanner.next();
if("exit".equals(tempFlag))
run();
else
login();
}
}
}
/**
* 用户注册
* */
public void regis(){
}
/**
* 文件传输
* @throws ClassNotFoundException
* */
@SuppressWarnings("unchecked")
public void fileTransfers() throws IOException, ClassNotFoundException{
//定义客户端与服务端传输的对象为Map
Map<String,Object> mapSend = new HashMap<String,Object>();
Map<String,Object> mapReceive = new HashMap<String,Object>();
if(null != user){
System.out.println("请输入本机文件的绝对路径: .........(如 d:\\a.txt)");
String path = scanner.next();
File file = null;
file = new File(path);
while(!file.exists()){
System.out.println("该文件不存在,请重新输入......");
path = scanner.next();
file = new File(path);
}
SocketFile scoketFile = new SocketFile();
scoketFile.setFileName(file.getName());
scoketFile.setFilePath(file.getAbsolutePath());
scoketFile.setFile(file);
mapSend.put("file", scoketFile);
mapSend.put("flag", 3);
// 获取输出流
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(mapSend);
out.flush();
//获取服务器响应
in = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
mapReceive = (Map<String, Object>) in.readObject();
if(null != mapReceive){
if("1".equals(mapReceive.get("flag")+"")){
System.out.println("文件传输成功,返回主菜单请安任意键......");
scanner.next();
run();
}else{
System.out.println("文件传输失败,返回主菜单请输入【exit】,重新传输文件请安任意键......");
String flag = scanner.next();
if("exit".equals(flag))
run();
else
fileTransfers();
}
}else{
throw new RuntimeException("接收服务器的数据不存在");
}
}else{
System.out.println("您还没有登陆....请先登陆");
login();
}
}
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8090);
// String path = "d:\\a.txt";
SocketFileClient client = new SocketFileClient(socket);
System.out.println("**************客户端已经启动*****************");
client.setPriority(4);
client.start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}