哦,总结 !( 通信阶段前期总结)

[size=medium][color=olive] 看了下上一次写的的总结,还是11年10月份的……
一直都不太喜欢写,或者说,总是以一副淡定,慵懒静默的姿态在学着。每次有所感悟心得,想写一篇的时候,也还是过后就觉得没必须的。其实没什么让自己的生活忙成了这样,国家总统都还有工作和生活。现在感知这不是一个很好的习惯,下决心尽量去改善。\(^o^)/~
下面是对这7天以来,对通信阶段所学知识的一个小总结:

一、完成的任务:

(1)实现服务器和客户端的互联:当有一个客户端连接进来的时候,服务器端启用一个线程来处理客户端发送过来的请求。
抽象出来,要做的有:
1.创建服务器对象,分配好实现连接时的端口号
2.在服务器端建立连接,返回连接套接S
3.在客户端建立连接,要指明所要连接的服务器的IP地址和端口号port

服务器端:[/color][/size]

	public void setServer(int port) {
try {
// 创建一个服务器对象,如果端口号超出范围或者已经被占用,则抛出异常
java.net.ServerSocket so = new java.net.ServerSocket(port);
// 让服务器进入循环等待状态
while (true) {// 等待客户机连接,连接后生成一个Socket对象,如果没有客户机连接进来则程序在此阻塞
java.net.Socket client = so.accept();
// 创建线程对象,并启动线程
ServerThread st = new ServerThread(client, jta);
st.start();
}
} catch (IOException e1) {
e1.printStackTrace();
}

}


[size=medium][color=olive]客户端:

[/color][/size]
// 创建客户端
public java.net.Socket setClients(java.net.InetAddress ip, int port) {
// 创建客户端,并将其连接到指定 IP 地址的指定端口号。(指定的端口号必须与服务器随即分配的端口号一致)
try {
s = new java.net.Socket(ip, port);
} catch (IOException e) {
e.printStackTrace();
}
return s;
}


[size=medium][color=olive](2)服务器和客户端的对讲:在客户端和服务器端分别创建一个显示界面,界面上包含一个多行文本区域(java.awt.TextArea jta)和一个单行文本显示区域(javax.swing.JTextField jtf)还有一个发送按钮(javax.swing.JButton jb)组件。
实现当客户端在在单行文本区域(jta)输入发送消息,点击发送按钮(jb)过后,服务器接收到消息并显示在多行文本区域(jtf)中;同理,服务器在单行文本区域输入发送消息,点击发送按钮过后,客户端接收到消息并显示在多行文本区域中。
实现方法也很简单,上面已经讲过服务器和客户端的互联了,实现互联后,我们可以通过得到连接套接S的输入输出流来进行读取和写出数据。

得到S的输入输出流:[/color][/size]

	// 创建输入流
InputStream ins = s.getInputStream();
// 创建输出流
OutputStream ins = s.getOutputStream();


[size=medium][color=olive] 然后要做的就是在在发送按钮上添加一个动作监听器(java.awt.event.ActionListener),当点击按钮时候,调用write()方法用得到的输出流写出输入框(jtf)的信息,并清空输入框:[/color][/size]

// 信息写入 :信息发送出去,输入框清空
public void write() {
try {
// 得到输出流
OutputStream ous = s.getOutputStream();
//创建数据输出流对象
DataOutputStream dos = new DataOutputStream(ous);
// 获得输入框信息,将输入框的信息按字节顺序写出到输出流中。
dos.writeBytes(jtf.getText());
ous.flush();
// 清空输入框
jtf.setText("");
} catch (IOException e) {
e.printStackTrace();
}
}



[size=medium][color=olive] 与此同时在另一端建立一个线程,不停读取数据(如果写出信息的一端是客户端,就在服务器端进行读取):[/color][/size]

public void read() {
while (true) {
try {// 不断读取数据
// 创建输入流
InputStream ins = s.getInputStream();
while (ins.available() > 0) {// 当有数据可读时,读取数据到字节数组b
int count = 0;
// 创建一个字符串缓冲区
StringBuffer stb = new StringBuffer();
char c;
while (ins.available() > 0) {
// 读取个客户机发来的一个字节
int i = ins.read();
// 将输入的一个字节转化为char类型
c = (char) i;
// 将得到的字符加入字符串缓冲区
stb.append(c);
}

// 将读入的字节转为字符串
String str = stb.toString();
System.out.println(str);
count++;
// 将读取到的数据显示到JTextArea中
ta.append("收到来自客户端的第" + count + "条信息:" + str + "\t\n");

}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}


[size=medium][color=olive](3)简单的服务器和客户端的画板交互:在客户端和服务器端分别创建一个显示界面,给界面窗体添加鼠标监听器,当点击释放鼠标后,可以实现画直线,并且在任一端画直线,另一端可以同步显示出来。
交互画板的实现和客户机服务器的对讲原理相同,差别只在于读取数据类型的不同,交互画板需要创建一个基本数据输入输出流(DataInputStream/DataOutputStream)来输入输出一条直线的两个坐标点位置。[/color][/size]

	// 获得套接的输入流,并创建基础数据输入流
InputStream ins = s.getInputStream();
DataInputStream dis = new DataInputStream(ins);// 得到套接的输出流,创建原始数据类型输出流
OutputStream ous = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(ous);

[size=medium][color=olive] 其实对于任何程序,理清事件发生的流程顺序了,实现就都不困难了。比如实现画板,因为读取数据是一个连续不断的过程,所以应该建立一个线程来进行读取,而每一次画了一条直线之后才需要写出数据,所以,只用在画线后调用就可以了。
(4)服务器和客户端之间的文件传输:实现在一段画直线或者椭圆,另一端同步显示出来;同时,一端通过文件选择器发送一个文件,另一端可以接受,并且保存到指定路径。我只写了从客户端发送文件,服务器接受文件。
实现文件传输有很多种方法,我用的是最复杂的一种方法,制定协议,就是制定读取写出的格式(比如先读取类型,是画图还是传文件,再读取文件名字长度,文件名字,文件正文长度,文件正文内容…),然后严格按照格式一板一眼的写过去,然后读取进来。
此处最混乱的是,要区分好输入输出的对象,是文件,还是客户端或者服务器,比如对于创建基本数据输入输出流就有关于输入输出到S中和输入输出到文件中的:[/color][/size]

// 得到套接的输出流,创建原始数据类型输出流
OutputStream ous = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(ous);
// 创建基于文件的原始数据类型输出流
OutputStream ous = new FileOutputStream(ServerThread.path);DataOutputStream dos = new DataOutputStream(ous);


[size=medium][color=olive]二、在完后该阶段任务中遇到的一些错误:

(1)关于服务器客户端连接的异常分析:

[b]1.java.net.BindException:Address already in use: JVM_Bind:[/b]该异常发生在服务器端进行new ServerSocket(port)操作时。异常的原因是以为与port一样的一个端口已经被启动,并进行监听。即上一次的运行还没关闭,又重新点击了运行。


[b]2.java.net.ConnectException: Connection refused: connect:[/b]该异常发生在客户端进行new Socket(ip, port)操作时,发生的原因或者是具有ip地址的机器不能找到,或者是该ip存在,但找不到指定的端口进行监听。出现该问题,首先检查客户端的ip和port是否写错了,如果正确则从客户端ping一下服务器看是否能ping通,如果能ping通(服务器端把ping禁掉则需要另外的办法),则看在服务器端的监听指定端口的程序是否启动。


[b]3.java.net.SocketException: Socket is closed:[/b]该异常在客户端和服务器均可能发生。异常的原因是己方主动关闭了连接后(调用了Socket的close方法)再对网络连接进行读写操作。


[b]4.java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error):[/b]该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset)。简单的说就是在连接断开后的读和写操作引起的。


[b]5.java.net.SocketException: Broken pipe:[/b]该异常在客户端和服务器均有可能发生。在第4个异常的第一种情况中(也就是抛出SocketExcepton:Connect reset by peer:Socket write error后),如果再继续写数据则抛出该异常。这两个异常的解决方法是首先确保程序退出前关闭所有的网络连接,其次是要检测对方的关闭连接操作,发现对方关闭连接后自己也要关闭该连接。


(2)空指针异常:S获得输入输出流时候的空指针异常,连接对象s的异常,一般是因为重新new了一个S所在类的对象,故而在非建立连接的类中用S时候,要记得传值过去。


(3)服务器和客户端两端画线出来位置总是不对
一个原因可能是调用的读写方法不对,比如writeByte(),然后readInt()就有可能丢失数据,第二个原因就是写出和读取时候的变量顺序要保持一致,不能这边写出x1,x2,然后那边读取x2,x1,第三个原因就是变量的个数,类型一定要对应。这些都是处理IO流重要注意的细节问题。


三、小点感想
在完成次阶段的任务时候,费了不少时间,但是,进度并不是很快,算是很慢,尤其是文件传输写了两天。

犯了很多的错误,主要还是监听传值的错误,和IO的错误。

发现了自己很多的不足,对以前所学的知识并没有掌握的很好。突然的发现自己关于流的所有知识都忘干净了,连InputStream是抽象类,不能被实例化都记不着了o(╯□╰)o 故而,总结还真是很重要,以前太懒了,看到别人每学一个内容时候,都将知识要点和所犯的错误写的清清楚楚,很惭愧。所以,下决心改了。

收获也有不少,对自己而言的最重要的是兴趣慢慢提高了,因为兴趣对自己真的很重要。其余的,没什么能阻挡住自己。并且看到了很多人的优秀和努力,更有激情和动力了。


最后,这篇总结好像写的很是混乱,看的到的人,看的懂的人看不懂的人,都可以吱下声给个意见~~没意见下次我也会写的更好。[/color][/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值