在了解socket编程之前,我们先来了解一下读写数据的数据流类中一些需要注意的东西。
BufferedReader与DataInputStream的区别:
通常我们常用到的字节输入输出流有BufferedReader与PrintWriter,DataInputStream和DataOutputStream这两对。这些类都属于java.io包。
那么两者之间有什么区别呢?
区别就是前者有个缓冲区,假如我们人为设置为100k(不设置亦可,有默认值),当这个缓冲区存储的内容达到100k的时候,类对象才会进行读入或写入操作。
而Stream的两个对象是没有缓冲区的,它们是收到什么数据就即刻进行读出和写入。
所以在进行socket编程的时候,这两对最好不要交替使用,因为当有数据存到前面提到的缓存里的时候,stream对象没有办法读到缓存里的东西,所以会造成数据的丢失。
在这里我们另外说一说PrintWriter类,先看看比较常用的两个构造方法:
在第二个构造方法中,参数2指明该对象是否自动将缓冲区里的数据流自动刷出,一般来说我们可以采用第二种构造方法,将参数2设为true。
否则,在每次用PrintWriter对象调用printXXX方法的时候,后面就要紧接着使用flush方法。
比如:
PrintWriter pw = new PrintWriter(socket.getOutputStream);
pw.println(“写出数据”);
pw.flush();
如果你不这么做的话,pw对象可能会因为你要写出的数据并未到达缓冲区指定大小而不作任何操作。这个时候你的线程就会阻塞!!所以关于这一点务必小心。
Java里的Socket工作模式:
在socket编程中我们基本上需要用到这些类:
SocketServer、Socket、BufferedReader与PrintWriter(或者DataInputStream与DataOutputStream)。
在服务器中,首先新建一个服务器socket对象:
ServerSocket srvSocket = new ServerSocket(nPort);
一旦接收到请求,则生成一个socket对象:
Socket socket = srvSocket.accept();
然后创建流对象:
BufferedReader bf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
客户端里直接进行连接然后创建流对象即可:
Socket socket = new Socket(hostAddr, nPort);
Socket编程基础Java实现:
其实在实现过程中遇到挺多很细节但是又很让人蛋疼的问题,比如前面提到的PrintWriter对象要么初始化的时候就设定为自动刷出缓存区内容,要么就每次写操作后面调用flush方法。下面给出实现方法:
客户端实现:
客户端实现的功能是这样的,输入一些特定的字符串,比如:DATE,BYE,DOY,DOM,DOW什么的,然后让服务器判断输入的是什么命令,然后服务器调用Calendar类返回对应的日期和时间信息。
我希望能从控制台读取用户输入的信息,所以设计了如下代码:
复制代码
BufferedReader inSys = new BufferedReader(new InputStreamReader(System.in));
while((string = inSys.readLine()) != null && string.length() != 0)
{
System.out.println("客户端这边输入的命令是"+string);
pw.println(string);
System.out.println("服务器返还的数据是"+bf.readLine());
//ctrl+z or Enter to terminate the loop
}
复制代码
这样的话,但凡是用户按了ctrl+z或者是Enter键,则结束循环。
下面给出客户端完整实现代码:
View Code
服务器实现:
设计服务器的时候,对进行数据读写操作的类应用Runnable接口,这样即可实现多线程,因为服务器没可能只对一个客户端提供服务的,所以写练习程序的时候直接写多线程的即可,从最基本的练起没必要,进度太慢。
在服务器的主方法里面,我们通过一个无限循环来不断地接受新发现的连接请求:
复制代码
ServerSocket srvSocket = new ServerSocket(8888);
while(true) //服务器是需要一直运行的,这样可以不断地监听和接收新的socket连接
{
Socket socket = srvSocket.accept(); //收到新的请求
System.out.println("收到新的socket连接请求");
ServerThread sThread = new ServerThread(socket);
Thread thread = new Thread(sThread);
thread.start();
//上面的三行代码,不妨直接写成:
//new Thread(new ServerThread(socket)).start();
}
复制代码
这样的话,服务器即可一直运行。
具体操作数据的方法写在从接口继承来的run方法即可,这个方法是必须被重载的。