Java,
Java,
刚开始接触通信时,心里就有点畏惧,因为觉得网络怎么想都一定很难,而自己的编程能力又很差。但是慢慢接触后觉得其实也没有自己想的那么高大上,在这里主要就是来总结下自己到目前为止了解以及掌握的知识,以及遇到的一些问题。
1.网络编程都是由客户端及服务器来组成。
客户端和服务器可以等同于打电话,客户端是拨电话的那方,而服务器则是等待电话连入的那方。
1)客户端的编程步骤:
A.建立网络连接
客户端第一步都必须先建立网络连接,建立网络连接时需要得到服务器的ip地址与端口号,建立连接后即会在客户端与服务器之间建立一个虚拟的连接,从而可以进行数据间的传递。
B.交换数据
连接建立以后,就可以通过这个连接交换数据了。交换数据严格按照协议进行,由客户端发送一个请求数据到服务器,服务器反馈一个响应数据给客户端,如果客户端不发送请求则服务器端就不响应。此步骤可重复进行。
C.关闭网络连接
在数据交换完成以后,关闭网络连接,释放程序占用的系统资源,结束网络编程。
2)服务器的编程步骤:
服务器一般实现程序的核心逻辑以及数据存储等核心功能。
A.监听端口
服务器启动以后开放给客户端一个端口,等待客户机的连接,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址。
B.获得连接
当客户端连接到服务器端时,服务器端就可以获得一个连接,服务器端和客户端通过该连接进行数据交换。
一般在服务器端编程中,当获得连接时,需要开启专门的线程处理该连接,每个连接都由独立的线程实现。
C.交换数据
服务器端通过获得的连接进行数据交换。
服务器端的数据交换也是可以多次进行的。
在数据交换完成以后,关闭和客户端的连接。
D.关闭连接
当服务器程序关闭时,需要关闭服务器端,通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭。
2.TCP编程
1)客户端
A.建立Socket连接
Socket client = new Socket(ip,port);
B. 网络数据交换
从连接中获得输入流和输出流,然后将需要发送的数据写入连接对象的输出流中,在发送完成以后从输入流中读取数据即可。示例代码如下:
InputStream ins = client.getInputStream();
OutputStream ous = client.getOutputStream();
这里获得的只是最基本的输出流和输入流对象,还可以根据需要,将这些获得到的基本流对象包装成其他流对象如DataOutputStream,从而方便数据的操作。
C. 关闭网络连接
client.close();
2)服务器端
A. 监听端口
ServerSocket server = new ServerSocket(port);
B. 获得连接
当有客户端连接到达时,建立一个和客户端连接对应的Socket连接对象,从而释放客户端连接对于服务器端端口的占用。
Socket socket= server.accept();
accept是一个阻塞方法,也就是当无连接时,该方法将阻塞程序的执行,直到出现客户端连接时才执行该行代码。获得的连接后,就可以直接通信,而服务器端的端口就被释放出来,又可以继续接受其它的连接了。
C. 进行网络数据交换
服务器端需要首先读取发送过来的数据,然后进行处理以后再发送给客户端。
D.关闭服务器端连接
Server.close();
以上为TCP类型的客户端及服务器的编程步骤,接下来为通信协议的一些总结。
3.通信协议
1)通信协议的概念:
一个手机通话的流程如下:
这就可以认为是一个客户机与服务器的通信。
从上面我们可以得到通信的两个特点:
A. 通信的流程
首先要能连上服务器,连上后双方必须遵守严格约定的消息发送顺序。
B.通信消息格式的定义
客户端在连接通道上向服务器发送消息时,服务器必须知道,凭什么界定收到的数据
算是“一条”消息。当两台机器通信时,必须定义一个规则,且双方严格遵守。
如:以换行符来作为一条消息结束的判定。
通信协议可以理解为:规定通信双方的通信流程和数据格式的规则,要参与通信的双方都必须严格遵守规则发送数据。
2.完成文本消息及文件的传输
当只进行文本之间的通信时我们可以以换行符来判断一句话的结束,但当我们要实现一个文件的传输时,靠换行符肯定无法实现。但是无论是文本消息还是文件,我们在InputStream流上进行读取时读取到的都是一个一个的字节,所以我们可以按照以下的协议来达到传输文本消息和文件的目的。
1)消息类型
当传送的消息为文本消息时,我们需要得到消息的内容及要传送的目标;而当传送文件时,我们需要得到文件的名字和文件的数据以及要传送的目标。如下图所示:
2) 消息由消息头和消息体构成
a)消息头:每条消息类型的消息头都是一样的。
◆消息总长totalLen: 用一个int(4个字节)来表示这条消息的总字节数即消息头和消息体的总长度。
◆消息类型type: 用一个byte(1个字节)来表示这条消息的类型,如type = 1时为文本消息,当type = 2时为文件。
◆目标的账号destNum: 用一个int(4个字节)来记录要发送的目标的账号。
一个消息头如下图所示:
b) 消息体:消息体根据消息类型的不同而不同
◆文本消息(type = 1):文本的内容,且其长度MsgLen = totalLen-4-1-4
◆文件(type = 2):需要文件的字节长度及文件的名字(固定以256个byte表示,不足补二进制0)
3)协议定义
发送方发消息时必须按照规定的格式和顺序来写入到输出流对象中,服务器读入时为:
A.先读取消息的总长度totalLen;
B.再读取消息的类型type;
C.然后读取消息的发送目标destNum;
D.若type = 1,则读取与文本同长度的字节数即totalLen-4-1-4,然后转成字符串;
E.若type = 2,则读取256个字节,转成字符串,去掉最后的空格后作为文件名;然后读取长度为totalLen-4-1-4-256 个字节,存入到文件中。
4.在实际编程中出现的错误及注意点
1)在进行文本传输时忘记以”\r\n”结尾导致服务器无法读取一句话;
2)从流中读取字节,填充字节数组时,没有使用read(要填充的数组)方法,而是调用readFully()方法,这样做更为安全。网络通信中,当发送大的数据量时,有这样一种可能:一部分数据已发送到对方,有一部分数据还在本地的网卡缓存中,如果调用read()方法,可能会提前返回而没有读取到足够的数据,在传送大块数据(如一次传送一个较大文件时)可能会出错,而readFully()方法会一直等待,读取到数组长度的所有数据后,才会返回。
3)在将Byte数组转成字符串时使用了toString()函数,导致出现乱码,应该使用new String(数组名)。
其实只要掌握了通信的流程后,就可以实现服务器与客户端之间的通信了,剩余的就是将其更加完善,添加更多的功能及界面。我觉得代码并没有附上的必要,所以在这里就不附上代码了。这就是我这一阶段的一个总结与回顾,因为自己对于知识的消化吸收特别慢,编程效率也比较低,但是只要一个阶段一个阶段慢慢完成,一点一点的完善,我觉得就足够了。下一阶段我的目标:
1.开始小组的项目;
2.通信方面添加私聊。
相关文章
- 暂无相关文章
用户点评