`
19941021
  • 浏览: 6159 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
最近访客 更多访客>>
社区版块
存档分类
最新评论
  • ayaome: ...
    java
  • 19941021:     明白了!谢谢了!
    java
  • ayaome: head属于LinkList类的属性你加个static关键字, ...
    java
  • 19941021:      这是因为在主函数中调用遍历链表的方法时要传入链表头的 ...
    java
  • ayaome: public static LinkNode head=nul ...
    java

Java SE通信开发小结(1)

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

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

        那么什么叫做协议呢?通俗的说就是两个人之间定义的一个口号,或一个约定
        你们按照自己的约定可以明白对方的意思,机器之间明确自己进行的操作。
       
         下面用代码简单实现以下发送聊天消息和文件:
         制定协议:
         消息:消息总长(int)+消息类型(byte)+消息内容(byte[])+目标客户账号(int)
        文件:文件数据总长(int)+数据类型(byte)+目标客户账号(int)+文件名(byte[256])
             +文件内容(byte[])

/**
 *界面等代码就省略了,只写下服务器和客户端的传输数据的功能实现
 *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);
	}
}



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




该方法代码实现随后见通信(2)




[/size]
分享到:
评论

相关推荐

    SAP ABAP与JAVA之间通过RFC传递数据实例

    #### 小结 本案例详细展示了如何通过RFC实现在SAP ABAP与JAVA应用程序之间的数据交换。通过配置JCo服务器程序以及编写相应的ABAP和JAVA代码,可以实现跨系统的数据传输和处理功能。这对于集成不同技术平台的应用...

    (超赞)JAVA精华之--深入JAVA API

    综上所述,本文深入探讨了 Java API 的各个方面,涵盖了从基础的 Java SE 到高级的 Web 开发和技术扩展等内容。这些知识点不仅对于初学者非常重要,对于想要进一步提升技能的开发者来说也是非常有价值的参考资料。

    JDBC使用小结

    JDBC,全称为Java Database Connectivity,是Java编程语言中用于规范客户端程序如何访问数据库的应用程序接口,它提供了标准的API让Java程序可以连接并操作各种类型的数据库系统。JDBC的本质是一套标准化的接口,...

    简单音乐播放器

    #### 七、实验小结 通过本项目的开发实践,不仅掌握了Java语言的基本编程技巧,还深入学习了多媒体处理、网络通信等相关领域的知识。更重要的是,这个过程中培养了团队合作能力和解决问题的能力。未来还可以考虑...

    基于hadoop的海量文本处理系统

    #### 四、前期工作小结 - **Hadoop高可用性修正**:针对Hadoop 0.12版本进行了高可用性的改进。 - **文本流数据处理框架**:从Nutch框架出发,创建了一套文本流数据处理的基础框架。 - **Eclipse插件开发**:开发了...

    深析Synchronized关键字(小白慎入,深入jvm源码,两万字长文)

    ### 三、小结 Synchronized关键字在Java并发编程中扮演着重要角色,它提供了一种简单的线程安全机制。从Java SE 1.6开始,通过引入偏向锁和轻量级锁,显著提高了多线程环境下的性能。理解Synchronized的工作原理和锁...

Global site tag (gtag.js) - Google Analytics