java socket实现两个客户段或多个客户端之间通信
java socket实现两个客户段或多个客户端之间通信。大家能够给我一个详细的讲解吗?
[解决办法]
数据包。这样一来,我们可以发出较大的数据包,而且处理进程也能加快。
注意和我们打开的几乎所有数据流一样,它们都要进行缓冲处理。本章末尾有一个练习,清楚展现了假如我
们不对数据流进行缓冲,那么会得到什么样的后果(速度会变慢)。
无限while 循环从BufferedReader in 内读取文本行,并将信息写入System.out,然后写入
PrintWriter.out。注意这可以是任何数据流,它们只是在表面上同网络连接。
客户程序发出包含了"END"的行后,程序会中止循环,并关闭Socket。
下面是客户程序的源码:
//: JabberClient.java
// Very simple client that just sends
// lines to the server and reads lines
// that the server sends.
import java.net.*;
import java.io.*;
public class JabberClient {
public static void main(String[] args)
throws IOException {
// Passing null to getByName() produces the
// special "Local Loopback" IP address, for
542
// testing on one machine w/o a network:
InetAddress addr =
InetAddress.getByName(null);
// Alternatively, you can use
// the address or name:
// InetAddress addr =
// InetAddress.getByName("127.0.0.1");
// InetAddress addr =
// InetAddress.getByName("localhost");
System.out.println("addr = " + addr);
Socket socket =
new Socket(addr, JabberServer.PORT);
// Guard everything in a try-finally to make
// sure that the socket is closed:
try {
System.out.println("socket = " + 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);
for(int i = 0; i < 10; i ++) {
out.println("howdy " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} finally {
System.out.println("closing...");
socket.close();
}
}
} ///:~
在main()中,大家可看到获得本地主机IP 地址的InetAddress 的三种途径:使用null,使用localhost,
或者直接使用保留地址127.0.0.1。当然,如果想通过网络同一台远程主机连接,也可以换用那台机器的IP
地址。打印出InetAddress addr 后(通过对toString()方法的自动调用),结果如下:
localhost/127.0.0.1
通过向getByName()传递一个null,它会默认寻找localhost,并生成特殊的保留地址127.0.0.1。注意在名
为socket 的套接字创建时,同时使用了InetAddress 以及端口号。打印这样的某个Socket 对象时,为了真
正理解它的含义,请记住一次独一无二的因特网连接是用下述四种数据标识的:clientHost(客户主机)、
clientPortNumber(客户端口号)、serverHost(服务主机)以及serverPortNumber(服务端口号)。服务
程序启动后,会在本地主机(127.0.0.1)上建立为它分配的端口(8080)。一旦客户程序发出请求,机器上
下一个可用的端口就会分配给它(这种情况下是1077),这一行动也在与服务程序相同的机器
(127.0.0.1)上进行。现在,为了使数据能在客户及服务程序之间来回传送,每一端都需要知道把数据发到
哪里。所以在同一个“已知”服务程序连接的时候,客户会发出一个“返回地址”,使服务器程序知道将自
543
己的数据发到哪儿。我们在服务器端的示范输出中可以体会到这一情况:
Socket[addr=127.0.0.1,port=1077,localport=8080]
这意味着服务器刚才已接受了来自127.0.0.1 这台机器的端口1077 的连接,同时监听自己的本地端口
(8080)。而在客户端:
Socket[addr=localhost/127.0.0.1,PORT=8080,localport=1077]
这意味着客户已用自己的本地端口1077 与127.0.0.1 机器上的端口8080 建立了 连接。
大家会注意到每次重新启动客户程序的时候,本地端口的编号都会增加。这个编号从1025(刚好在系统保留
的1-1024 之外)开始,并会一直增加下去,除非我们重启机器。若重新启动机器,端口号仍然会从1025 开
始增值(在Unix 机器中,一旦超过保留的套按字范围,数字就会再次从最小的可用数字开始)。
创建好Socket 对象后,将其转换成BufferedReader 和PrintWriter 的过程便与在服务器中相同(同样地,
两种情况下都要从一个Socket 开始)。在这里,客户通过发出字串"howdy",并在后面跟随一个数字,从而
初始化通信。注意缓冲区必须再次刷新(这是自动发生的,通过传递给PrintWriter 构建器的第二个参
数)。若缓冲区没有刷新,那么整个会话(通信)都会被挂起,因为用于初始化的“howdy”永远不会发送出
去(缓冲区不够满,不足以造成发送动作的自动进行)。从服务器返回的每一行都会写入System.out,以验
证一切都在正常运转。为中止会话,需要发出一个"END"。若客户程序简单地挂起,那么服务器会“掷”出一
个违例。
大家在这里可以看到我们采用了同样的措施来确保由Socket 代表的网络资源得到正确的清除,这是用一个
try-finally 块实现的。
套接字建立了一个“专用”连接,它会一直持续到明确断开连接为止(专用连接也可能间接性地断开,前提
是某一端或者中间的某条链路出现故障而崩溃)。这意味着参与连接的双方都被锁定在通信中,而且无论是
否有数据传递,连接都会连续处于开放状态。从表面看,这似乎是一种合理的连网方式。然而,它也为网络
带来了额外的开销。本章后面会介绍进行连网的另一种方式。采用那种方式,连接的建立只是暂时的
[解决办法]
两种做法
每个客户端既是客户端又是服务器端
或者通过一个中间服务器端通信
[解决办法]
用多线程中间服务器端通信,每个线程维护一个客户组的通信
------解决方案--------------------
针对维护多个客户端:
采用客户端/服务器方式通讯的话,那无论你是两个客户端还是多个,都需要维护一个客户端列表!~
列表的维护可以再服务器端也可以分布到客户端拷贝,但程序实现上还是单独维护服务器端简单些;
如果做的好,那还要不断维护客户端在线的状态,如果有客户端程序,那可以通过程序事件向服务器或客户广播自己的状态,
当然也可以采用服务器主动向客户端发出查询来验证状态;
哈哈,发现一个不求代码的帖子,扯两句!
[解决办法]
2.如何开发一个Server-Client模型的程序
开发原理:
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
{建立服务器}
import java.net.*;
import java.io.*;
public class Server
{
private ServerSocket ss;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public Server()
{
try
{
ss = new ServerSocket(10000);
while (true)
{
socket = ss.accept();
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String line = in.readLine();
out.println("you input is :" + line);
out.close();
in.close();
socket.close();
}
ss.close();
}
catch (IOException e)
{}
}
public static void main(String[] args)
{
new Server();
}
}
这个程序建立了一个服务器,它一直监听10000端口,等待用户连接。在建立连接后给客户端返回一段信息,然后结束会话。这个程序一次只能接受一个客户连接。
{建立客户端}
import java.io.*;
import java.net.*;
public class Client
{
Socket socket;
BufferedReader in;
PrintWriter out;
public Client()
{
try
{
socket = new Socket("xxx.xxx.xxx.xxx", 10000);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
BufferedReader line = new BufferedReader(new InputStreamReader(System.in));
out.println(line.readLine());
line.close();
out.close();
in.close();
socket.close();
}
catch (IOException e)
{}
}
public static void main(String[] args)
{
new Client();
}
}
这个客户端连接到地址为xxx.xxx.xxx.xxx的服务器,端口为10000,并从键盘输入一行信息,发送到服务器,然后接受服务器的返回信息,最后结束会话。
第二步 多个客户同时连接
在实际的网络环境里,同一时间只对一个用户服务是不可行的。一个优秀的网络服务程序除了能处理用户的输入信息,还必须能够同时响应多个客户端的连接请求。在java中,实现以上功能特点是非常容易的。
设计原理:
主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。运用Thread类或Runnable接口来实现是不错的办法。
{实现消息共享}
import java.io.*;
import java.net.*;
public class Server extends ServerSocket
{
private static final int SERVER_PORT = 10000;
public Server() throws IOException
{
super(SERVER_PORT);
try
{
while (true)
{
Socket socket = accept();
new CreateServerThread(socket);
}
}
catch (IOException e)
{}
finally
{
close();
}
}
//--- CreateServerThread
class CreateServerThread extends Thread
{
private Socket client;
private BufferedReader in;
private PrintWriter out;
public CreateServerThread(Socket s) throws IOException
{
client = s;
in = new BufferedReader(new InputStreamReader(client.getInputStream(), "GB2312"));
out = new PrintWriter(client.getOutputStream(), true);
out.println("--- Welcome ---");
start();
}
public void run()
{
try
{
String line = in.readLine();
while (!line.equals("bye"))
{
String msg = createMessage(line);
out.println(msg);
line = in.readLine();
}
out.println("--- See you, bye! ---");
client.close();
}
catch (IOException e)
{}
}
private String createMessage(String line)
{
xxxxxxxxx;
}
}
public static void main(String[] args) throws IOException
{
new Server();
}
}
这个程序监听10000端口,并将接入交给CreateServerThread线程运行。CreateServerThread线程接受输入,并将输入回应客户,直到客户输入"bye",线程结束。我们可以在createMessage方法中,对输入进行处理,并产生结果,然后把结果返回给客户。
[解决办法]
你还没有登录社区!用户名 密 码登录 有效期 浏览器进程 永久 一个月一天 一小时 页面登录注册 找回密码首 页 文 章 博 客 论 坛 下 载 图 书 炎黄盈动 专题文章 博客 资源下载 图书推荐 相册搜索 当前位置:中文JAVA技术网 >> 专题文章 >> Java基础 >> 查看专题文章
关于Java Socket编程的详细介绍
阅读次数: 810次 发布时间: 2008-04-23 09:31:09发布人: 沃尔夫
来源: csai
事实上网络编程简单的理解就是两台计算机相互通讯数据而已.对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了。Java SDK提供一些相对简单的Api来完成这些工作。Socket就是其中之一。对于Java而言,这些Api存在与java.net 这个包里面。因此只要导入这个包就可以准备网络编程了。
网络编程的基本模型就是客户机到服务器模型。简单的说就是两个进程之间相互通讯,然后其中一个必须提供一个固定的位置,而另一个则只需要知道这个固定的位置,并去建立两者之间的联系。然后完成数据的通讯就可以了。这里提供固定位置的通常称为服务器,而建立联系的通常叫做客户端。基于这个简单的模型,就可以进入网络编程啦。
Java对这个模型的支持有很多种Api。而这里我只想介绍有关Socket的编程接口。对于Java而言已经简化了Socket的编程接口。首先我们来讨论有关提供固定位置的服务方是如何建立的。Java提供了ServerSocket来对其进行支持,事实上当你创建该类的一个实力对象并提供一个端口资源你就建立了一个固定位置可以让其他计算机来访问你。ServerSocket server=new ServerSocket(6789);这里稍微要注意的是端口的分配必须是唯一的。因为端口是为了唯一标识每台计算机唯一服务的。另外端口号是从0~65535之间的,前1024个端口已经被Tcp/Ip 作为保留端口,因此你所分配的端口只能是1024个之后的。好了,我们有了固定位置.现在所需要的就是一根连接线了。该连接线由客户方首先提出要求。因此Java同样提供了一个Socket对象来对其进行支持。只要客户方创建一个Socket的实例对象进行支持就可以了。Socket client=new Socket(InetAddress.getLocalHost(),5678);客户机必须知道有关服务器的IP地址。对于着一点Java也提供了一个相关的类InetAddress。该对象的实例必须通过它的静态方法来提供。它的静态方法主要提供了得到本机IP 和通过名字或IP直接得到InetAddress的方法。
好了.上面的方法基本可以建立一条连线让两台计算机相互交流了。可是数据是如何传输的呢?事实上I/O操作总是和网络编程息息相关的。因为底层的网络是继续数据的,除非远程调用,处理问题的核心在执行上。否则数据的交互还是依赖于IO操作的.所以你也必须导入java.io这个包。java的IO操作也不复杂,它提供了针对于字节流和Unicode的读者和写者,然后也提供了一个缓冲用于数据的读写。
BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); PrintWriter out=new PrintWriter(server.getOutputStream());
上面两句就是建立缓冲并把原始的字节流转变为Unicode可以操作。而原始的字节流来源于Socket的两个方法。getInputStream()和getOutputStream()方。分别用来得到输入和输出。那么现在有了基本的模型和基本的操作工具。我们可以做一个简单的Socket例程了。
服务方:
import java.io.*; import java.net.*; public class MyServer { public static void main(String[] args) throws IOException{ ServerSocket server=new ServerSocket(5678); Socket client=server.accept(); BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); while(true){ String str=in.readLine(); System.out.println(str); out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); } }
这个程序的主要目的在于服务器不断接收客户机所写入的信息只到。客户机发送"End"字符串就退出程序。并且服务器也会做出"Receive"为回应。告知客户机已接收到消息。
客户机代码:
import java.net.*; import java.io.*; public class Client{ static Socket server; public static void main(String[] args)throws Exception{ server=new Socket(InetAddress.getLocalHost(),5678); BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); PrintWriter out=new PrintWriter(server.getOutputStream()); BufferedReader wt=new BufferedReader(new InputStreamReader(System.in)); while(true){ String str=wt.readLine(); out.println(str); out.flush(); if(str.equals("end")){ break; } System.out.println(in.readLine()); } server.close(); } }
客户机代码则是接受客户键盘输入,并把该信息输出,然后输出"End"用来做退出标识。
这个程序只是简单的两台计算机之间的通讯。如果是多个客户同时访问一个服务器呢?你可以试着再运行一个客户端,结果是会抛出异常的。那么多个客户端如何实现呢?
其实,简单的分析一下,就可以看出客户和服务通讯的主要通道就是Socket本身。而服务器通过accept方法就是同意和客户建立通讯。这样当客户建立Socket的同时。服务器也会使用这一根连线来先后通讯。那么既然如此只要我们存在多条连线就可以了。那么我们的程序可以变为如下:
服务器:
import java.io.*; import java.net.*; public class MyServer { public static void main(String[] args) throws IOException{ ServerSocket server=new ServerSocket(5678); while(true){ Socket client=server.accept(); BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); while(true){ String str=in.readLine(); System.out.println(str); out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); } } }
这里仅仅只是加了一个外层的While循环。这个循环的目的就是当一个客户进来就为它分配一个Socket直到这个客户完成一次和服务器的交互,这里也就是接受到客户的"End"消息。那么现在就实现了多客户之间的交互了。但是问题又来了。这样做虽然解决了多客户,可是是排队执行的。也就是说当一个客户和服务器完成一次通讯之后下一个客户才可以进来和服务器交互,无法做到同时服务。那么要如何才能同时达到既能相互之间交流又能同时交流呢?很显然这是一个并行执行的问题了。所以线程是最好的解决方案。
那么下面的问题是如何使用线程.首先要做的事情是创建线程并使得其可以和网络连线取得联系,然后由线程来执行刚才的操作,要创建线程要么直接继承Thread要么实现Runnable接口,要建立和Socket的联系只要传递引用就可以了,而要执行线程就必须重写run方法。而run方法所做的事情.就是刚才单线程版本main所做的事情。因此我们的程序变成了这样:
import java.net.*; import java.io.*; public class MultiUser extends Thread{ private Socket client; public MultiUser(Socket c){ this.client=c; } public void run(){ try{ BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); //Mutil User but can't parallel while(true){ String str=in.readLine(); System.out.println(str); out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); }catch(IOException ex){ }finally{ } } public static void main(String[] args)throws IOException{ ServerSocket server=new ServerSocket(5678); while(true){ //transfer location change Single User or Multi User MultiUser mu=new MultiUser(server.accept()); mu.start(); } } }
我的类直接从Thread类继承了下来。并且通过构造函数传递引用和客户Socket建立了联系。这样每个线程就有了一个通讯管道,同样我们可以填写run方法,把之前的操作交给线程来完成。这样多客户并行的Socket就建立起来了。
-5 -3 -1 - +1 +3 +5
评分:0
我来说两句内容:
发表评论
相关文章? [IDE工具/测试工具] Eclipse使用简介 浏览:38 发表日期[09-05-06] ? [SOA/ESB/JMS] SOA主要目标是业务与IT之间保持一致 浏览:5 发表日期[09-05-06] ? [Java基础] Java编译器中对string对象的优化 浏览:15 发表日期[09-05-06] ? [Java基础] 浅谈Java 同步机制 浏览:36 发表日期[09-05-05] ? [业界新闻] 开源专家布兰肯霍恩:甲骨文将后悔收购Sun 浏览:34 发表日期[09-05-05] ? [业界新闻] MDA技术BPM理念亮相建设行业企业信息化应用发展研讨会(图) 浏览:17 发表日期[09-05-05] ? [业界新闻] SaaS成09软博会关注重点 论坛凸显四大亮点 浏览:11 发表日期[09-05-05] ? [数据库持久层] Mysql 添加用户的两种方法 浏览:32 发表日期[09-05-05] ? [业界新闻] G&B:“甲型H1N1”西班牙语木马病毒惊现网络 浏览:28 发表日期[09-05-05] ? [开源框架] Java开源缓存平台Terracotta 3.0版本发布 浏览:27 发表日期[09-05-05] ? [业界新闻] 防范“猪流感”在网络世界传播 警惕垃圾邮件 浏览:18 发表日期[09-05-04] ? [实用技巧] 一位软件测试工程师2个月面试总结 浏览:178 发表日期[09-05-04] 技术专栏+-专题技术
--多线程编程 --Socket/RMI --Ajax --应用服务器 --WebService/EAI --J2EE --Servlet/JSP --Applet/Swing/SWT --数据库持久层 --JavaMail --J2ME/WAP/智能卡 --Java认证考试 --设计模式 --团队管理 --开源框架 --SOA/ESB/JMS
+-新手入门 --业界新闻 --Java基础 --实用技巧 --IDE工具/测试工具 --XML 参与讨论 Web开发
(JSP/Servlet/JSF/Tapestry/Spring/..)
Java入门基础
(环境/安装/语法/调试/编译/执行/..)
数据库开发
(JDBC/JDO/Hibernate/EJB3/..)
Java高级编程
(多线程/IO/算法/设计模式/网络/..)
Ajax框架
(Flex/Prototype/dojo/YUI/DWR/EXT/..)
开发工具
(Eclipse/NetBeans/IDEA/...)
UI客户端开发
(Eclipse插件开发/Applet/Swing/..)
J2EE服务器
(Tomcat/JBoss/WebLogic/WebSphere/..)
资源共享
(图书/视频/项目/代码/..)
集成架构
(/SOA/ESB/EAI/OSGi/SCA/SDO/..)
畅谈W3C,共同学习CSS
综合问题
(性能/压力/测试/JVM/安全/集群/..)
找茬寻宝
(正在进行中......)
J2ME移动受限设备开发
开源技术讨论
CN-JAVA在线翻译
详细解释 专业解释 简单解释
关于CN-JAVA | 广告服务 | 联系方式 | 友情链接 | 网站地图 | 版权声明 | 网站统计
CopyRight(C) 2001-2008 Jackliu AT炎黄盈动. All Rights Reserved.
京ICP备05051608号 Actionsoft Co., Ltd Tel:010-62962320/2343/3450 Fax: 010-62961851
[解决办法]