一、实现思路
使用socket通信的一些方法来实现socket通信,客户端和服务端两边需要约定好通信的接口Port(尽量选高的),客户端需要服务端的IP地址,以实现数据交流。
同时,客户端和服务端需要约定好数据传输的方式,比如我这里用 '!' 作为传输数据结束的标志,用'@'实现不同类型数据的分隔。
还有就是服务端那边需要保存排行榜的信息,由于那时候我还不会用数据库,所以用对象流将数据存入服务端的文件中,每次开启服务器就读取这个文件的信息。
在我这个程序里面,客户端向服务端发送的有两种请求,上传数据(上传用户得分),下载数据(获取排行榜),所以需要在服务端判断用户的请求,并执行对应的操作。
二、注意事项
1)socket通信的时候要选好接口号Port,不能出现选择的接口号被其他服务占用。
2)客户端中的Socket 对象,要输入服务端的IP地址和接口号Port,我的代码里面为了方便,把自己的电脑作为服务端,所以用InetAddress.getByName("localhost")来获取本地IP地址,以实现socket通信
3)代码区给出的代码里面的ranking是排行榜信息,本博文没有给出
三、socket通信的常用模板
1)客户端向服务端发送数据
//这里为了不想多次修改本机的IP地址,直接获取本机IP地址 Socket socket = new Socket(InetAddress.getByName("localhost"), 7879); //输出流
OutputStream os = socket.getOutputStream(); //设置每次传输的数据量 BufferedOutputStream bos = new BufferedOutputStream(os, 16); //获取排行榜的请求 String news = new String("downlLoad"); // 下载数据 //一般是用字节流进行传输 byte[] bb = news.getBytes(); // 发送数据包 bos.write(bb); bos.flush();
2)客户端接收服务端信息
//向服务端发送请求后,准备接受服务端出传入的信息 InputStream is = socket.getInputStream(); //设置每次传输的数据量 BufferedInputStream bis = new BufferedInputStream(is, 16); byte[] b = new byte[16]; //order记录获取的整个数据 char[] order = new char[600]; //表示order中的字符数,也可以当作字符串的长度 int tot = 0; //获取服务端传入的信息 while ((bis.read(b) != -1)) { //结束判断 boolean end = false; for (int i = 0; i < 16; i++) { if ((char) b[i] == '!') { //约定号用 '!' 作为结束标记 end = true; break; } //将服务端传入的信息转化为字符 order[tot++] = (char) b[i]; } if (end) { break; } //这个不能少,重置获取信息的字节数组 b = new byte[16]; } //关闭客户端 socket.close();
3)服务端接收客户端信息
try { //服务端和客户端双方约定好接口号 ServerSocket serverSocket = new ServerSocket(7879); Socket socket = null; socket = serverSocket.accept(); InputStream is = socket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is, 16); byte[] b = new byte[16]; //order代表客户端传入的请求 char[] order = new char[16]; while ((bis.read(b)) != -1) { boolean end = false; for (int i = 0; i < 16; i++) { order[i] = (char) b[i]; if(order[i] == '!') { //约定好用'!'作为传输结束标志 end = false; break; } } if(end) { break; } } } catch (IOException e) { e.printStackTrace(); }
4)服务端向客户端发送信息
OutputStream os = socket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os, 16); byte[] bb = ranking.toString().getBytes(); byte[] ends = new String("!").getBytes(); // 输入结束命令 bos.write(bb);// 发送数据包 bos.flush(); bos.write(ends); bos.flush();
四、代码区
类Cilent
package component; import java.io.*; import java.net.*; public class Client { public static void main(String[] args) { new Client(null); } public Client(GameOver gameover) { } //数据下载,从服务端获取排行榜信息 public boolean downLoad(String name , Key key) { try { //这里为了不想多次修改本机的IP地址,直接获取本机IP地址 Socket socket = new Socket(InetAddress.getByName("localhost"), 7879); //输出流 OutputStream os = socket.getOutputStream(); //设置每次传输的数据量 BufferedOutputStream bos = new BufferedOutputStream(os, 16); //获取排行榜的请求 String news = new String("downlLoad"); // 下载数据 //一般是用字节流进行传输 byte[] bb = news.getBytes(); // 发送数据包 bos.write(bb); bos.flush(); //向服务端发送请求后,准备接受服务端出传入的信息 InputStream is = socket.getInputStream(); //设置每次传输的数据量 BufferedInputStream bis = new BufferedInputStream(is, 16); byte[] b = new byte[16]; //order记录获取的整个数据 char[] order = new char[600]; //表示order中的字符数,也可以当作字符串的长度 int tot = 0; //获取服务端传入的信息 while ((bis.read(b) != -1)) { //结束判断 boolean end = false; for (int i = 0; i < 16; i++) { if ((char) b[i] == '!') { //约定号用 '!' 作为结束标记 end = true; break; } //将服务端传入的信息转化为字符 order[tot++] = (char) b[i]; } if (end) { break; } //这个不能少,重置获取信息的字节数组 b = new byte[16]; } //关闭客户端 socket.close(); //将从服务器获取的排行榜信息组成排行榜 return new RankingList(name,key).print(new String(order)); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } public boolean upData(char mode, String name, String score) { try { //本地服务端 Socket socket = new Socket(InetAddress.getByName("localhost"), 7879); OutputStream os = socket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os, 16); //客户端和服务端约定好数据处理方式,以便互相“理解” String news = new String("upLoad" + mode + "@" + name + "@" + score + "@"); byte[] bb = news.getBytes(); bos.write(bb);// 发送数据包 bos.flush(); //关闭客户端 socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } }
类Sever
package component; import java.io.*; import java.net.*; public class Server { //保存排行榜信息 private Ranking ranking = null; public static void main(String args[]) { new Server(); } public Server() { //先在服务端本地读取排行榜的数据,用对象流 ObjectInputStream rank_in = null; try { File file = new File("ranking.txt"); // 文件不存在,则开一个新的 if (!file.exists()) { file.createNewFile(); ranking = new Ranking(); } else { // 文件存在,直接读取 rank_in = new ObjectInputStream(new FileInputStream(file)); ranking = (Ranking) rank_in.readObject(); } } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (ClassNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } finally { if (rank_in != null) { try { rank_in.close(); } catch (IOException e) { e.printStackTrace(); } } } //及时保存 this.save(); try { //服务端和客户端双方约定好接口号 ServerSocket serverSocket = new ServerSocket(7879); Socket socket = null; while (true) { socket = serverSocket.accept(); InputStream is = socket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is, 16); byte[] b = new byte[16]; //order代表客户端传入的请求 char[] order = new char[16]; while ((bis.read(b)) != -1) { boolean end = false; for (int i = 0; i < 16; i++) { order[i] = (char) b[i]; if(order[i] == '!') { //约定好用'!'作为传输结束标志 end = false; break; } } if(end) { break; } //第一种请求,上传用户数据 if (order[0] == 'u' && order[1] == 'p' && order[2] == 'L' && order[3] == 'o' && order[4] == 'a' && order[5] == 'd') { //分别代表关卡,用户名,分数 char section = order[6]; String name = null; String score = null; //代表客户端传入的信息 char[] in = new char[50]; //字符串长度 int index = 0; //index当前代表的是什么,(关卡,用户名,分数) int mode = 1; //System.out.println("first"); //这里是处理上一次数据剩余的数据 for (int i = 8; i < 16; i++) { if (order[i] != '@') { //@是数据类型分隔符 in[index++] = order[i]; } else { in[index++] = ' '; // @分隔name和score if (mode == 1) { mode++; name = new String(in); // 第一次为姓名 } else { score = new String(in);//第二次为分数 mode++; break; } in = new char[50]; index = 0; } } //System.out.println("second"); order = new char[16]; // 为读入下一组 //这里是继续读取 while ((bis.read(b)) != -1 && mode < 3) { for (int i = 0; i < 16; i++) order[i] = (char) b[i]; System.out.println(order); for (int i = 0; i < 16; i++) { if (order[i] != '@') { in[index++] = order[i]; } else { System.out.println(mode); in[index++] = ' '; // 空格分隔name和score if (mode == 1) { mode++; name = new String(in); // 第一次为姓名 } else { mode++; score = new String(in);//第二次为分数 break; } in = new char[50]; index = 0; } } //数据读取完毕,退出 if(mode == 3) { break; } } //System.out.println("third: "+mode); //System.out.println("third"); ranking.add(section, name, score);//向Ranking对象添加新的数据,具体判断在ranking里面 //System.out.println(ranking.toString()); this.save(); //System.out.println("end"); } else { //第二种请求,获取排行榜 //System.out.println("download"); OutputStream os = socket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os, 16); byte[] bb = ranking.toString().getBytes(); byte[] ends = new String("!").getBytes(); // 输入结束命令 bos.write(bb);// 发送数据包 bos.flush(); bos.write(ends); bos.flush(); } break; } } } catch (IOException e) { e.printStackTrace(); } } public void save() { ObjectOutputStream rank_out = null; try { // 为保证及时性,先删除文件然后再创建新的 File file = new File("ranking.txt"); file.delete(); file.createNewFile(); rank_out = new ObjectOutputStream(new FileOutputStream("ranking.txt")); rank_out.writeObject(ranking); System.out.println(ranking); rank_out.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (rank_out != null) { try { rank_out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }