java socket实现两个客户段或多个客户端之间通信。大家能够给我一个详细的讲解吗?
------解决方案--------------------
------解决方案--------------------
首先有两个类一个是客户端,,一个是服务端,客户端连接到指定IP的服务器的端口,,服务器监听该端口 ,,,然后就输入输出流,,服务器端要用非阻塞式实现多个用户同时连接
------解决方案--------------------
//<<think in java >>的一章1 5 . 2 . 1 一个简单的服务器和客户机程序
这个例子将以最简单的方式运用套接字对服务器和客户机进行操作。服务器的全部工作就是等候建立一个连
接,然后用那个连接产生的Socket 创建一个InputStream 以及一个OutputStream。在这之后,它从
InputStream 读入的所有东西都会反馈给OutputStream,直到接收到行中止(END)为止,最后关闭连接。
客户机连接与服务器的连接,然后创建一个OutputStream。文本行通过OutputStream 发送。客户机也会创
建一个InputStream,用它收听服务器说些什么(本例只不过是反馈回来的同样的字句)。
服务器与客户机(程序)都使用同样的端口号,而且客户机利用本地主机地址连接位于同一台机器中的服务
540
器(程序),所以不必在一个物理性的网络里完成测试(在某些配置环境中,可能需要同真正的网络建立连
接,否则程序不能工作——尽管实际并不通过那个网络通信)。
下面是服务器程序:
//: JabberServer.java
// Very simple server that just
// echoes whatever the client sends.
import java.io.*;
import java.net.*;
public class JabberServer {
// Choose a port outside of the range 1-1024:
public static final int PORT = 8080;
public static void main(String[] args)
throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Started: " + s);
try {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
System.out.println(
"Connection accepted: "+ socket);
BufferedReader in =
new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
// Output is automatically flushed
// by PrintWriter:
PrintWriter out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),true);
while (true) {
String str = in.readLine();
if (str.equals("END")) break;
System.out.println("Echoing: " + str);
out.println(str);
}
// Always close the two sockets...
} finally {
System.out.println("closing...");
socket.close();
}
} finally {
s.close();
}
}
} ///:~
可以看到,ServerSocket 需要的只是一个端口编号,不需要IP 地址(因为它就在这台机器上运行)。调用
541
accept()时,方法会暂时陷入停顿状态(堵塞),直到某个客户尝试同它建立连接。换言之,尽管它在那里
等候连接,但其他进程仍能正常运行(参考第14 章)。建好一个连接以后,accept()就会返回一个Socket
对象,它是那个连接的代表。
清除套接字的责任在这里得到了很艺术的处理。假如ServerSocket 构建器失败,则程序简单地退出(注意必
须保证ServerSocket 的构建器在失败之后不会留下任何打开的网络套接字)。针对这种情况,main()会
“掷”出一个IOException 违例,所以不必使用一个try 块。若ServerSocket 构建器成功执行,则其他所有
方法调用都必须到一个try-finally 代码块里寻求保护,以确保无论块以什么方式留下,ServerSocket 都能
正确地关闭。
同样的道理也适用于由accept()返回的Socket。若accept() 失败,那么我们必须保证Socket 不再存在或者
含有任何资源,以便不必清除它们。但假若执行成功,则后续的语句必须进入一个try-finally 块内,以保
障在它们失败的情况下,Socket 仍能得到正确的清除。由于套接字使用了重要的非内存资源,所以在这里必
须特别谨慎,必须自己动手将它们清除(Java 中没有提供“破坏器”来帮助我们做这件事情)。
无论ServerSocket 还是由accept()产生的Socket 都打印到System.out 里。这意味着它们的toString方法
会得到自动调用。这样便产生了:
ServerSocket[addr=0.0.0.0,PORT=0,localport=8080]
Socket[addr=127.0.0.1,PORT=1077,localport=8080]
大家不久就会看到它们如何与客户程序做的事情配合。
程序的下一部分看来似乎仅仅是打开文件,以便读取和写入,只是InputStream 和OutputStream 是从
Socket 对象创建的。利用两个“转换器”类InputStreamReader 和OutputStreamWriter ,InputStream 和
OutputStream 对象已经分别转换成为Java 1.1 的Reader 和Writer 对象。也可以直接使用Java1.0 的
InputStream 和OutputStream 类,但对输出来说,使用Writer 方式具有明显的优势。这一优势是通过
PrintWriter 表现出来的,它有一个过载的构建器,能获取第二个参数——一个布尔值标志,指向是否在每
一次println()结束的时候自动刷新输出(但不适用于print()语句)。每次写入了输出内容后(写进
out),它的缓冲区必须刷新,使信息能正式通过网络传递出去。对目前这个例子来说,刷新显得尤为重要,
因为客户和服务器在采取下一步操作之前都要等待一行文本内容的到达。若刷新没有发生,那么信息不会进
入网络,除非缓冲区满(溢出),这会为本例带来许多问题。
编写网络应用程序时,需要特别注意自动刷新机制的使用。每次刷新缓冲区时,必须创建和发出一个数据包
(数据封)。就目前的情况来说,这正是我们所希望的,因为假如包内包含了还没有发出的文本行,服务器
和客户机之间的相互“握手”就会停止。换句话说,一行的末尾就是一条消息的末尾。但在其他许多情况
下,消息并不是用行分隔的,所以不如不用自动刷新机制,而用内建的缓冲区判决机制来决定何时发送一个