坦克大战--Java类型 ---- (3)实现socket通信
一、实现思路
使用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通信的更多相关文章
- 坦克大战--Java类型
写在前面 Java编译器下载教程(真的良心):https://blog.csdn.net/Haidaiya/article/details/81230636 本项目为本人独自制作,请各位尊 ...
- 坦克大战--Java类型 ---- (2)按键设置和用户名的输入
一.实现思路(emmmm,这个地方我很大程度参照了别人的写法) 由于键盘按键众多,因此使用选择框JComboBox 进行按键选择,点击一个JButton 按钮后,读取所有选择框中的内容,然后存到一 ...
- 坦克大战--Java类型 ---- (1)音乐播放
实现原理 我用接口java.applet.AudioClip实现音乐播放,那么我们需要了解这个接口的情况. 我们主要使用其中的三个方法: (1)void loop(); //循环播放(2)void p ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
- 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- java和C#之间SOCKET通信的问题
转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...
- Java和C#的socket通信相关(转)
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- Java进阶(四十七)Socket通信
Java进阶(四十七)Socket通信 今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...
- Java实现简单的socket通信
今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了. 今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有pa ...
随机推荐
- (Java多线程系列二)线程间同步
Java多线程间同步 1.什么是线程安全 通过一个案例了解线程安全 案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 先来看一个线程不安全的例子 class Sell ...
- Hibernate和Mybatis框架的对比
Hibernate:是一个标准的ORM(对象关系映射)框架.入门门槛较高,不需要程序员写sql,sql语句自动生成.但是就造成对sql语句进行优化.修改比较困难.应用场景:适用于需求变化不多的中小型项 ...
- jq获取页面中checkbox已经选中的checkbox
var len=$("input[name='bike']:checked").length; //len为0未选中
- vue添加外部js
1.新建节点 const s = document.createElement("script"); 2.设置节点属性 s.type = "text/javascript ...
- JAVA异常及其异常处理方式
异常处理 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的.比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error:如果你用Syste ...
- LeetCode---Sort && Segment Tree && Greedy
307. Range Sum Query - Mutable 思路:利用线段树,注意数据结构的设计以及建树过程利用线段树,注意数据结构的设计以及建树过程 public class NumArray { ...
- Laravel 中如何区别 Model 或者是 Builder?
User::where('id',1)->update([]) 和 User::find(1)->update([]) 有异曲同工之效. 额? 当你通过 Laravel 与数据库交 ...
- python正则表达式解析(re)
正则表达式的使用方法主要有4种: re.search(进行正则匹配), re.match(从头开始匹配) re.findall(找出所有符合条件的字符列表) re.split(根据条件进行切分) ...
- Groovy脚本基础全攻略
1 背景 Groovy脚本基于Java且拓展了Java,所以从某种程度来说掌握Java是学习Groovy的前提,故本文适用于不熟悉Groovy却想快速得到Groovy核心基础干货的Java开发者(注意 ...
- delphi raise 语句: 抛出异常
//例1:begin raise Exception.Create('抛出异常');end;//例2:begin raise Exception.CreateFmt('%s %d', ['错误代码 ...