Java SE通信开发小结(1)

[size=medium]
[color=green]
通信项目做了好长时间,今天回过头,重新温习一下学过的知识,并总结一下知识。
既然讲到通信,那么首先就要提到一个问题:
什么是通信?
我在未学习通信之前的理解:
通信就是联网,不联网何来通信,联网之后进行数据传递就行了。
对服务器,客户端都只是一个模糊的概念,只知大概,不知全貌。
最可悲的是不知道数据是如何传递的。
学习后对通信的理解:
首先解释几个名词:
服务器:在几台电脑之间建立连接之前,等待连接的机器。
客户端:主动连接其他机器的机器。
每台机器都有一个ip地址,和0~65535端口(0~1024已有其他用途,自己连接时最好不要用)
网址与服务器地址的关系:服务器地址由9~10位数字组成,网址是一个域名,
两者是映射关系
常用的几个与网络有关的dos命令
1.ping netjava.cn 查看网络是否通畅
2.telnet [服务器地址] [端口号] 连接服务器的指定端口
3.netstat -an 查看和自己的机器通信的网络
4.tracert [网址] 跟踪你的机器与连接目标地址间的路由器

通信的途径就是:(核心就是协议)
1.服务器和客户端建立连接
2.获得两者的输入流,输出流
3.制定协议
4.根据服务器与客户端间制定的[u]协议[/u]进行数据的读,写解析

那么什么叫做协议呢?通俗的说就是两个人之间定义的一个口号,或一个约定
你们按照自己的约定可以明白对方的意思,机器之间明确自己进行的操作。

下面用代码简单实现以下发送聊天消息和文件:
制定协议:
消息:消息总长(int)+消息类型(byte)+消息内容(byte[])+目标客户账号(int)
文件:文件数据总长(int)+数据类型(byte)+目标客户账号(int)+文件名(byte[256])
+文件内容(byte[])
[/color]

/**
*界面等代码就省略了,只写下服务器和客户端的传输数据的功能实现
*Client:客户端
*Server:服务器
*/
package 通信;

import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {

// 启动主函数
public static void main(String[] args) {
Server se = new Server();
se.setServer(8732);
}

public void setServer(int port) {
try {
// 建立绑定在指定端口上的服务器对象
ServerSocket server = new ServerSocket(port);
while (true) { // 让服务器进处循环等待状态
Socket client = server.accept();
// 调用处理连接对象的方法去处理连接
calChat(client);
}
} catch (Exception ef) {
ef.printStackTrace();
}
}

// 处理客户机进入的连接对象
private void calChat(Socket client) {
try {
// 得到一个输出/输入流对象
OutputStream out = client.getOutputStream();
InputStream ins = client.getInputStream();
// 将输入流包装为DataInputStream方便读取原始类型的流
DataInputStream dins = new DataInputStream(ins);
while (true) {
// 开始读取数据:每一条消息
// 1.读消息长度
int totalLen = dins.readInt();
// 2.读取消息类型标识
byte flag = dins.readByte();
// 3.读取目标客户账号
int destNum = dins.readInt(); // 消息头解析完毕
// 根据消息的类型,读取消息体部分
if (flag == 1) {// 类型为1,是文本聊天消息,按其规则读取
// 创建对应消息体部分字节的长度的数据
byte[] data = new byte[totalLen - 4 - 1 - 4];
// 从流中读取data.length个字节放入数组中
dins.readFully(data);
String msg = new String(data);// 转成字符串
} else if (flag == 2) {// 文件数据包体解析
System.out.println("发送文件给:" + destNum);
byte[] data = new byte[256];
dins.readFully(data);// 读取256个字节做文件名字
// 解析出了文件名字,并去除末尾空格
String fileName = new String(data).trim();
// 余下的字节就是文件内容
data = new byte[totalLen - 4 - 1 - 4 - 256];// 文件字节数据总长
dins.readFully(data);// 读入文件的字节
// 保存文件到当前目录下:
FileOutputStream fous = new FileOutputStream(fileName);
fous.write(data);
fous.flush(); //将缓冲数据全部输出
fous.close(); //关闭文件输出流
} else {
client.close();
}
}
} catch (Exception ef) {
ef.printStackTrace();
}
}

}

//客户端
package 通信;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
private DataOutputStream dous;// 输出流对象

//发送字符串
private void writeString(DataOutputStream out, String str,int length) {
try {
byte[] data = str.getBytes(); //将字符串转化为字符数组
out.write(data); //向服务器发送数据
while(length>data.length){
out.writeByte('\0');//补二进制0
length--;
}
} catch (Exception ef) {
ef.printStackTrace();
}
}

//发送文本消息给目标账户
private void sendTextMsg(String msg, int account) {
try {
byte[] sb = msg.getBytes();// 得到消息的字节数
//消息总长=自身长度(int)+消息类型(byte)+账号(int)+消息内容(byte[])
int totalLen = 4 + 1 + 4 + sb.length;
dous.writeInt(totalLen); // 总长
dous.writeByte(1); // 类型:1为文本消息
dous.writeInt(account);// 写入目标用户号
dous.write(sb);// 写入消息内容
dous.flush();
} catch (Exception ef) {
ef.printStackTrace();
}

}

//发送指定的文件给目标用户
private void sendFile(String fileName, int destNum) {
try {
// 根据文件名创建文件对象
File file = new File(fileName);
// 根据文件对象,构造一个输入流
InputStream ins = new FileInputStream(file);
int fileDataLen = ins.available();// 文件数据总长
int totalLen = 4 + 1 + 4 + 256 + fileDataLen; // 得到了要发送数据包的总长
dous.writeInt(totalLen);
dous.writeByte(2);// 类型是2,即文件数据包
// 写入目标用户号
dous.writeInt(destNum);
// 文件名:得到文件的短名字
String shortFileName = file.getName();
// 写入文件名
writeString(dous, shortFileName,256);
byte[] fileData = new byte[fileDataLen];
ins.read(fileData);// 读入文件数据
dous.write(fileData);// 写出到服务器的流中
dous.flush(); // 刷新流
} catch (Exception ef) {
ef.printStackTrace();
}
}

//根据制定的服务器地址和端口连接服务器
public void LinkServer(String ip, int port) {
// 创建一个到服务器端的Socket对象
try {
Socket client = new Socket(ip, port);
// 得到输入输出流对象
InputStream ins = client.getInputStream();
OutputStream ous = client.getOutputStream();
// 将输出流包装为DataOutputStream对象
dous = new DataOutputStream(ous);
int num = 0;
while (true) {
System.out.println("登录服务器成功,请选择你要发的类型(1:聊天 2:文件:");

// 让用户从命令行输入要发送的文件名字
Scanner sc = new java.util.Scanner(System.in);
int type = sc.nextInt();
if (type == 1) {// 发文本
sendTextMsg("我要发送问文本了" +num++, 8380);
}
if (type == 2) {// 发文件,注这个文件必须存在
sendFile("d:\\wjh.txt", 8380);
}
num++;
}
} catch (Exception ef) {
ef.printStackTrace();
}
}

// 主函数
public static void main(String[] args) {
Client client = new Client();
client.LinkServer("localhost", 8732);
}
}


[color=blue]
其实除了这种发送方式还有其他方式:
你把文件(MyFile)和消息(MyMessage)用类分装,将前面发送的东西设置为属性,在属性里面定义,set和get方法
发送时,先创建输入,输出流对象ins,dous
写入对象类型标识flag(byte)
然后用对象输入流封装ObjectInputStream input=new ObjectInputStream(ins);
调用input.ReadObject();
根据flag的值用相应类的对象接收
我以前也是用这种方法
最后调用该类的get方法输出,就ok了
[/color]
[color=red]
[size=large]
[b]
该方法代码实现随后见通信(2)[/b]
[/size]
[/color]

[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值