做了太多时候的Web项目,Socket这么基础而又重要的接口都快忘掉了,虽然偶尔做做,但是都不大深入,刚好前段时间又做了点Socket类的应用,又对Socket接口有一些新的认识,先记下来
放在blog上马上就有人指出了我的错误,特此感谢,所以又拿到论坛上来等着大家拍,如有错误,欢迎指正
1.SocketStream截断字符
在FileStream里面最后一位截断字符是-1,这样在操作文件的时候就可以使用如下的判断:
BufferedReader buffer = new BufferedReader(new InputStreamReader(socket
.getInputStream(), "UTF-8"));
DataInputStream in = new DataInputStream(connection.getInputStream());
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
而这招在Socket里面是不灵的,因为如果这个判断要成立,需要对方Socket主动关闭,客户端收到EOF以后才能使得这个判断成立,否则对方不关,count永远得不到-1,就会一直阻塞在那里。
因为Socket接口能互相传送的东西是双方协议规定好的,什么字符都可能出现,这样只用-1来做截断判断是不对的,如果双方认定-1或者某些特殊字符可以作为截断标识那也可以,这样做只有当已知传递文件不会出现-1的时候才行,这种判断的习惯可能是来自于C语言,但是C语言是有一个EOF,而Java里面没有提供。
解决这个问题的办法,经过朋友指点变成了这样:
int BS=100,count=0;
byte[]buffer=new byte[BS];
int has_readed=0;
DataInputStream in = new DataInputStream(connection.getInputStream());
while ((count = in.read(buffer)) > 0 && has_readed < BS) {
int left=BS-has_readed;
out.write(buffer, 0, count>left?left:count);
has_readed+=count;
}
上面的代码变得复杂了许多,思路是这样的:
A.每次读取都是读指定长度的byte流,这样在协议里面写好长度,读取指定的内容,读取精确,无需阻塞,效率也高。
B.采用一个has_readed作为计数器,防止网络阻塞的情况下不能读到数据,增强程序的健壮性。
2.count = in.read(buffer)
这个东西看起来再普通不过,但以前没有仔细去想,也没有什么资料去分析过,这里让我们仔细看看,C语言里面允许一个方法返回两个参数,但是Java里面是非法的,然后这个in.read(byte b[])这个方法也做了类似的事情:
A.为read方法读到的buffer的个数,如果读不到值会返回-1。
B.read方法将读到的东西附给了buffer这个byte数组,这样就达到了返回两个参数的效果,因为数组是Object对象,这样将它作为参数传进去就可以将其赋值,基本类型是做不到这点,只有对象可以(大家用的多的是List,Map之类)。
3.byte还是String
最早接触Java的时候做Socket,就是用String类型来传输,很方便,双方接口处理起来都很简单而且更直观,这次接口传输的却是byte[],搞的我很郁闷,可能是我的Java基础并不够扎实(后来同事给的评语是你肯定是没怎么写过C……),byte[]就不爽了,就是一大堆莫名其妙的数字还要对各种类型做转化控制数位什么的,稍不小心就会出错。起初一直以为是客户那边有技术上的风格习惯,后来想想,这Socket可是语言之间的沟通桥梁,又不是单为你Java做的,像C语言这种没给你准备String这个类型啊。其实String类型还好,怎么说还能变通一下实现,有人说在Socket里面传递序列化的对象可就更麻烦拉。用byte[]数组对类型转换啥的也能更熟悉一些。
4.使用Excutor来代替Thread(内容源自Java Concurrency in Practice,如果需要找到详细内容,请参看原书第六章)
一道经典的面试题:Java有哪几种方式来实现线程?答:继承Thread和实现Runnable接口,但是1.5以后就不能这么回答,应该再加上java.util.concurrent,套用《Java并发编程实践》中的一句话:
无论何时当你看到这种形式的代码:
new Thread(runnable).start()
并且你可能最终希望获得一个更加灵活的执行策略时,请认真考虑使用Executor代替Thread
在使用Socket的时候我们经常会这样写:
ServerSocket socket = new ServerSocket(7001);
While(true){
final Socket connection = socket.accept();
Runnable task = new Runnable(){
public void run(){
//hanld reuqust code
}
};
new Thread(task).start();
}
这看上去似乎没问题,而且所有的教科书里面都这样写的,一个请求一个线程,无限制创建线程,在原型和产品开发的时候都表现良好,但是这种每任务每线程(thread-per-task) 方法存在实际的缺陷,特别是需要创建大量线程的时候会更加突出:
A.线程生命周期的开销
B.资源消耗量
C.稳定性
具体描述可以参看原书,所出现的问题是很容易理解的,所以即便你的程序还在使用1.4版本(Third party),如果大量依赖线程,特别是需要处理大量并发的情况下,应该采用java.util.concurrent提供的线程池,concurrent相对Thread更加稳定且功能丰富,可以使多线程并发程序有更为稳定的表现。
我们原来的接口程序就是采用原始的Thread,并发量要求达到500个,使我异常的头痛,那么如果采用Concurrent线程池的就能获得更好的并发性能并确保服务器的稳定性(可惜暂时没有机会实践)。
5.期待JDK7
JDK7现在正在开发阶段,目前的趋势是SUN将为JDK7添加对多核开发提供更好的支持,那么主要就是体现在java.util.concurrent上面,我目前正在阅读《Java并发编程实践》,争取有时间写个读书笔记什么的,要对并发开发保持持续的跟进学习。
前几天看到JavaEye新闻里面有一个人写的有关JDK7对多核开发的支持的疑问,也值得我们去思考一下:
第一点是java不能仅仅是提供支持线程开发包这么简单,而应该是像Scala、Erlang这种在语言级别就支持多核
第二点是面对即将到来的多核时代,如何利用好8核、16核这种处理器不仅仅是如何更好的发挥CPU的性能,因为即便你能发挥多核的潜力,但是你将不得不面对大量I/O操作的处理,I/O处理将会成为更为难缠的瓶颈,因为这种I/O资源是只能使用锁策略。
貌似这些东西还挺远,但是很有趣,还有一些Java想加入的语法糖,和对动态语言支持的大量的争论,真不知道JDK7会是个什么样子,总之Java已经越来越复杂越来越受软件界关注。
分享到:
- 2008-04-03 16:35
- 浏览 2712
- 评论(1)
- 论坛回复 / 浏览 (0 / 4522)
- 查看更多
相关推荐
总结起来,"Java Swing+Socket+Thread聊天程序"是一个基本的实时聊天应用,通过Java的GUI库构建用户交互界面,使用Socket进行网络通信,借助多线程处理并发连接,实现了简单的群聊功能。虽然它没有数据库支持,但...
以上就是`Android socket 学习记录 client端源码`的主要内容,通过学习和实践这部分代码,你可以掌握如何在Android客户端使用Socket与服务器进行通信,为开发实时聊天、文件传输等应用打下坚实的基础。在实际开发中...
具体实现上,可以使用Python的`socket`库创建UDP套接字,`threading`库管理线程,以及`queue`库来管理日志队列。以下是一个简单的示例: ```python import socket import threading import queue # 创建UDP套接字 ...
SocketTest支持多线程处理,确保在C#中通过`Thread`类创建并发线程,每个线程处理一个客户端连接。 6. **异常处理**:SocketTest在遇到错误时会给出反馈,这是通过C#的异常处理机制实现的,如`try-catch`块,捕捉和...
Java Socket IO Thread 整合大文件与上传下载是网络编程中的一个重要应用场景,特别是在处理大量数据交换时,如文件传输。Socket提供了低级别的网络通信接口,IO(Input/Output)用于处理数据流,而线程(Thread)则...
在本案例中,我们将聚焦于使用C#编程语言和WinForms来实现基于Socket的即时通讯系统。Socket是网络编程中的基本组件,它提供了进程间通信(IPC)的能力,尤其是跨网络的进程间通信。 首先,我们需要了解Socket的...
5. **计时上传**:为了计算上传时间,可以在开始发送文件前记录当前时间(例如使用`GetTickCount()`函数),并在所有数据发送完毕后再次获取时间,两者之差即为上传时间。 6. **关闭连接**:文件上传完成后,记得...
udpSocket->moveToThread(&thread); thread.start(); ``` 4. 实现数据收发功能。`QUdpSocket`提供了一系列的信号和槽,例如`readyRead()`信号会在有数据可读时触发,可以连接到相应的槽函数来处理接收到的数据。 `...
通常,我们会创建一个子线程(如AsyncTask或自定义Thread)处理Socket的I/O操作,防止因长时间阻塞而导致的ANR(Application Not Responding)错误。在子线程中,我们可以设置读写数据的逻辑,以及异常处理机制。 ...
在这个聊天程序中,我们可能会使用流式Socket,因为它提供了一种面向连接、可靠的数据传输方式,适合于需要保证数据完整性的应用,如聊天软件。 二、VB.NET中的Socket类 在VB.NET中,Socket类位于System.Net....
- 使用 `System.Threading.Thread` 类创建新的线程,然后在新线程的运行方法中处理与客户端的通信逻辑。 - 为了避免同步问题,可以使用 `Monitor`、`Mutex`、`Semaphore` 等同步原语来控制对共享资源(如数据缓冲...
4. **异常处理**:使用`try-catch`结构来捕获并处理可能出现的异常,如网络中断、Socket错误等,并记录异常信息。 #### 关键知识点总结 1. **Socket连接状态判断**: - 利用`ClientSocket.Connected`属性判断当前...
为了实现消息的广播,服务器需要维护一个客户端列表,记录所有在线的客户端Socket。当接收到一条新消息时,服务器遍历这个列表,通过`send()`函数将消息发送给每个客户端。这样,每个客户端都能接收到所有其他人的...
本实例源码“C#高性能大容量SOCKET并发完成端口例子完整实例源码”是针对C#开发者设计的,它提供了使用C#实现的基于完成端口(I/O Completion Ports, IOCP)技术的Socket并发处理解决方案,并包含了客户端的实现。...
在这个"Socket服务器例子"中,我们将探讨如何创建一个简单的Socket服务器,记录客户端连接,并发送信息到指定的Socket对象。 首先,我们需要了解Socket的基本概念。在Java中,`java.net.Socket`类代表客户端到...
### 使用Socket编程实现电子邮件发送的关键知识点 #### 一、Socket编程基础 Socket编程是一种网络通信方式,它允许不同计算机上的程序进行数据交换。在互联网上,每个设备都有一个唯一的IP地址,而Socket则是通过...
多线程的使用涉及到Thread类和Mutex、Semaphore等同步机制,以防止数据竞争和资源冲突。 服务器端的核心在于监听客户端的连接请求。Socket类的Listen方法用于设置服务器进入监听状态,Accept方法用于接收客户端的...
本主题将深入探讨如何使用C# WinForm和Socket技术来构建一个基本的即时聊天功能。Socket编程是网络通信的基础,它允许两个或多个设备通过网络进行数据交换。 首先,理解Socket的基本概念至关重要。Socket是网络编程...
- 用户可以在聊天窗口中输入消息,点击发送按钮后,消息将通过socket发送给服务器,并在界面中更新聊天记录。 3. **Threading库**: - Python的threading库支持多线程编程,这对于聊天室这样的实时应用至关重要。...
本篇文章将深入探讨如何使用C#构建一个多线程的Socket客户端,特别是针对聊天室场景。 标题中的"C# 多线程socket客户端"指的是在C#环境中,利用Socket类和多线程技术来创建一个能够并发处理多个连接的客户端应用。...