一、实现思路

使用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. MS11-080提权

    前提是你渗透进入了一台服务器 这是微软11年的第80个漏洞 每一个漏洞都有一个对应的kb(补丁) 这里我们直接在kali里面搜索 root@kali:~# searchsploit ms11- --- ...

  2. laravel 中first和find区别(总结一)

    检索单个模型/集合 除了从指定的数据表检索所有记录外,你也可以通过 find 或 first 方法来检索单条记录.这些方法不是返回一组模型,而是返回一个模型实例: // 通过主键取回一个模型... $ ...

  3. Ubuntu——配置JDK

    在Ubuntu下配置JDK环境 检查是否已经安装了JDK,执行以下命令: java -v 如果出现以下内容则说明没有安装: 程序 'java' 已包含在下列软件包中: * default-jre * ...

  4. MySQL——逻辑分层与存储引擎

    MySQL是最受欢迎的开源SQL数据库管理系统,由Oracle Corporation开发,分发和支持. MySQL网站(http://www.mysql.com/)提供有关MySQL软件的最新信息. ...

  5. 求平面上N点最远两点和最近两点距离

    最近两点,二分法 最远两点,凸包+找对踵点

  6. Struts ognl表达式语言几个符号

    #  获取非根元素值  . 动态都建map集合 $  配置文件取值 %  提供一个ognl表达式运行环境 <%@ page language="java" import=&q ...

  7. web搜索框的制作(必应)

    搜索框中我们输入一些字或者字母,为何下面就会有一些自动补齐的相关搜索,比如我在搜索输入框中输入一个字母e,下面就会出现饿了么,e租宝,ems等相关的搜索链接.然后经过百度,发现原来很多厂商的服务器早已 ...

  8. redis5.0编译安装

    ##################### linux下运行redis 1.下载源码 https://redis.io/ 2.将源码上传到服务器中,进行编译安装 a)可以使用rz进行上传(sz是将服务 ...

  9. PHP 生成器 yield理解

    如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...

  10. /etc/shadow字段信息

    root:$1$yOVPpScN$MlmYppDEYfwMMuDnthdIj.:18100:0:99999:7::: 与/etc/passwd文件中的登陆名称字段对应的登录名 加密后的密码 自上次修改 ...