一、实现思路

使用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++] = '\0'; // @分隔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++] = '\0'; // 空格分隔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();
}
}
}
} }

坦克大战--Java类型 ---- (3)实现socket通信的更多相关文章

  1. 坦克大战--Java类型

    写在前面       Java编译器下载教程(真的良心):https://blog.csdn.net/Haidaiya/article/details/81230636 本项目为本人独自制作,请各位尊 ...

  2. 坦克大战--Java类型 ---- (2)按键设置和用户名的输入

    一.实现思路(emmmm,这个地方我很大程度参照了别人的写法)   由于键盘按键众多,因此使用选择框JComboBox 进行按键选择,点击一个JButton 按钮后,读取所有选择框中的内容,然后存到一 ...

  3. 坦克大战--Java类型 ---- (1)音乐播放

    实现原理 我用接口java.applet.AudioClip实现音乐播放,那么我们需要了解这个接口的情况. 我们主要使用其中的三个方法: (1)void loop(); //循环播放(2)void p ...

  4. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  5. 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?

    这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...

  6. java和C#之间SOCKET通信的问题

    转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...

  7. Java和C#的socket通信相关(转)

    这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...

  8. Java进阶(四十七)Socket通信

    Java进阶(四十七)Socket通信   今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...

  9. Java实现简单的socket通信

    今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了. 今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有pa ...

随机推荐

  1. (Java多线程系列二)线程间同步

    Java多线程间同步 1.什么是线程安全 通过一个案例了解线程安全 案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 先来看一个线程不安全的例子 class Sell ...

  2. Hibernate和Mybatis框架的对比

    Hibernate:是一个标准的ORM(对象关系映射)框架.入门门槛较高,不需要程序员写sql,sql语句自动生成.但是就造成对sql语句进行优化.修改比较困难.应用场景:适用于需求变化不多的中小型项 ...

  3. jq获取页面中checkbox已经选中的checkbox

    var len=$("input[name='bike']:checked").length; //len为0未选中

  4. vue添加外部js

    1.新建节点 const s = document.createElement("script"); 2.设置节点属性 s.type = "text/javascript ...

  5. JAVA异常及其异常处理方式

    异常处理 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的.比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error:如果你用Syste ...

  6. LeetCode---Sort && Segment Tree && Greedy

    307. Range Sum Query - Mutable 思路:利用线段树,注意数据结构的设计以及建树过程利用线段树,注意数据结构的设计以及建树过程 public class NumArray { ...

  7. Laravel 中如何区别 Model 或者是 Builder?

    User::where('id',1)->update([])  和  User::find(1)->update([]) 有异曲同工之效.   额? 当你通过 Laravel 与数据库交 ...

  8. python正则表达式解析(re)

    正则表达式的使用方法主要有4种: re.search(进行正则匹配), re.match(从头开始匹配)  re.findall(找出所有符合条件的字符列表)  re.split(根据条件进行切分)  ...

  9. Groovy脚本基础全攻略

    1 背景 Groovy脚本基于Java且拓展了Java,所以从某种程度来说掌握Java是学习Groovy的前提,故本文适用于不熟悉Groovy却想快速得到Groovy核心基础干货的Java开发者(注意 ...

  10. delphi raise 语句: 抛出异常

    //例1:begin  raise Exception.Create('抛出异常');end;//例2:begin  raise Exception.CreateFmt('%s %d', ['错误代码 ...