java网络

输出流必须要注意的一些细节。

OutputStream—字节输出流

常用的实现类:
FileOutputStream—字节文件输出流,write数据后立刻写到文件中去
BufferedOutputStream—带缓冲区的字节输出流,数据会先存放到缓存取,缓冲区满的话会自动flush到目的地。
也就是说这个类写数据必须要调用flush方法,否则数据无法写到目的地,当然也可以调用close方法,这个方法关闭流的时候会自动flush

Writer—-字符输出流

FileWriter—字符文件输出流,write后,会将字符转换成字节缓存到底层的bytebuffer中去,如果满了(或者调用flush,close方法),才会输出到目的地
BufferedWriter—字符缓冲输出流,writer后,会将字符缓存起来,如果满了(或者调用了flush,close方法),才会输出到目的地
PrintWriter—-字符输出流(可看成也是一个包装类,带缓冲区的,与BufferedWriter功能相似) 可以设置自动刷新,使用println(xxx)方法,自动输出到目的地。
如果没有指定自动刷新,必须调用flush或者close方法

问题:

1.什么时候要用flush()方法?
上面的总结可以发现:字节流只有非Buffered的输出流才不需要调用flush() 或者使用了PrintWriter自动刷新了
BufferedOutputStream BufferedWriter PrintWriter(非自动刷新) 都需要显示的调用flush()方法

当然close的时候也会刷新,但是可能close的时候报错(这个方法会抛出异常),或者想及时的把数据发送给对方或者输出到文件,最好还是flush()一下。

2.什么时候用字符流,什么时候用字节流?
字符操作用writer(最好是BufferedWriter)效率更高,操作方法
如果操作需要换行字符的使用PrintWriter
操作二进制文件,图片,音频等数据的时候,用字节流(最好使用BufferedOutputStream,效率高)

3.网络传输过程中-Socket编程过程中应该怎么使用输出流,输入流?
发送图片,二进制文件,对象流等—最好使用BufferedOutputStream包装,然后输出字节流,需要flush
发送字符串—-最好用BufferedWriter或者PrintWriter包装,然后输出字符串,需要flush
另外:
socket读取的时候,read()操作是阻塞式的,也就是说,除非一端flush或者使用了非包装的字节流,这边才能读取到数据,当对方close关闭流的时候,才是真正的读取完毕

Java Socket设置timeout几种常用方式总结

可以先创建套接字再连接,也可以创建套接字时连接,但此时无法控制超时时长

建立连接timeout,暂时就叫 connect timeout;

socket.connect(new InetSocketAddress("www.ss.ssss", 8080), 2000);
设置connect timeout来控制连接建立的超时时间(不是绝对的,当设置的主机名不合法,比如我设置主机名为abc,会抛异常java.net.UnknownHostException: abc,但是此时connect timeout设置是不起作用的,测试得出的结论,仅供参考)。

读取数据timeout,暂时就叫so timeout。

socket = new Socket();
socket.setSoTimeout(int timeout)
通过设置so timeout可以控制流读取数据的超时时间。

java队列

使用实例

Queue queue = new LinkedList();
queue.offer("a");//添加一个元素
queue.poll()//返回第一个元素,并在队列中删除

问题

offer,add 区别:
一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
poll,remove 区别:
remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似, 但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。
peek,element区别:
element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。

线程等待与唤醒

java.lang.InterruptedException: sleep interrupted异常
当线程sleep后被打断会出现此异常
interrupt方法确实是打断睡眠状态了,在使用线程池中,等线程启动完毕,开始运行,却执行了exe.shutdown()方法,该方法使得主线程强行打断子线程的sleep状态,因此抛出此异常,根据实际情况,可以忽略此该异常。

打断后,线程的状态中有值被记为true
isInterrupted()可以用来测试线程是否已经中断(即被从睡眠状态中唤醒过)
interrupted()测试当前线程是否已中断并将状态置为false。

sleep

Thread.sleep()让当前线程进入不可运行状态一段时间。线程继续保持它所获取的监视器(也就是操作系统中的互斥锁)——即如果线程当前处于同步块或方法中,则没有其他线程可以进入此块或方法。如果另一个线程调用t.interrupt()会唤醒sleep的线程。注意,sleep()是一种静态方法,这意味着它总是影响当前线程(执行睡眠方法的线程)。一个常见的错误是用t.sleep期望不同的线程休眠,但实际上是当前线程休眠。

wait(),notify()

Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程(具体哪一个由JVM决定),而notifyAll()是唤醒所有的线程(哪一个线程会优先执行时取决于JVM线程调度的)。
注意:这些方法在一个需要互斥访问的对象上调用。调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内。

区别

wait被用作多线程互斥访问同一份资源
sleep用于某一线程时间上暂停

java.net.SocketException: sendto failed: EINVAL (Invalid argument)

可能原因:端口号写错
DatagramPacket packet1 = new DatagramPacket(data, data.length, InetAddress.getByName(msg.getReceiverIp()), udpPort);
udpPort这个端口号的值是有范围的,写错了,会报这个错误