1.设定服务器顺循环等待:
服务器不能只连接一个客户机就退出——你可以将ServerSocket的accept()方法放在一个循环中调用:进行一个客户机,当服务器与这个客户机通信完毕后,服务器就再次进入循环中,重新调用accept()方法等待下一客户机连接进入,代码示例如下:
while(true){
Socket client=server.accept();//让服务器在while中等待:阻塞状态
//从连接对象上得到输入输出流对象. . .
|
当然,如果你要控制服务器的启动和停止,硬编码while的条件为true可不是个好主意。
2.读取客户机字符串分析
至此,我们知道了服务器创建的基本流程,但有一件事还没弄明白,一个字符串是如何通过网络被发送到客户机的?如何读取客户机发来的消息?
发送字符串分析:
请注意,发送字符串时,首先调用字符串的getBytes()方法,得到组成这个字符串的字节数组,发送出的实际上是这个字节数组。请测试如下代码,示例了在字符串和和字节数组之间的转换:
String s="Hello!";
byte[] data=s.getBytes();
for(int i=0;i<data.length;i++){
System.out.println(i+"个字节是"+data[i]
+" 二进制是:"+Integer.toBinaryString(data[i]));
}
//再将字节组转为字符串
String src=new String(data);
System.out.println("生成的字符串是: "+src);
|
运行后,输出的结果如下:
0个字节是72 二进制是:1001000
1个字节是101 二进制是:1100101
2个字节是108 二进制是:1101100
3个字节是108 二进制是:1101100
4个字节是111 二进制是:1101111
5个字节是33 二进制是:100001
生成的字符串是: Hello!
|
我的目地只是要说明:字符串是由字节组成的,字节是二进制位组成的——在网络上发送的,其实是一个个字节(byte),或者说是组成每一个字节的一个二进制位(bit)。从网络中读取信息时,情况也是一样的。从InputStream对象中,一次只能读到一个字节,然后,再将这些字节组装为一个String对象——前提是对方发送的是一串文本,而不是一张图片,如下代码:
public void setUpServer(int port){
try{
//建立绑定在指定端口上的服务器对象
ServerSocket server=new ServerSocket(port);
System.out.println("服务器创建成功!"+port);
while(true){ //让服务器循环等待
Socket client=server.accept();
//从连接对象上得到输入输出流对象
OutputStream out=client.getOutputStream();
InputStream ins=client.getInputStream();
String s="你好,欢迎来javaKe.com\r\n";
byte[] data=s.getBytes();//取得组成这个字符串的字节
out.write(data); //用输出对象发送数据
out.flush();//强制输出
int in=0; //一个字节一个字节的读取客户机的输入
while(in!=13){//如果读到不是13,即回车字符
in=ins.read();
System.out.println("读到的一个是: "+in);
}
System.out.println("客户机按了回车,退出:"+in);
client.close();//半闭与这个客户机的连接
}
}catch(Exception ef){ef.printStackTrace();}
}
|
运行如上程序,在命令行通过telnet连接后,输入一些字符,如图1.13所示。
可以看到,在telnet输入界面中,每输入一个字符(串),马上会被发送给服务器。在以上代码示例中,我们还改进了让服务能循环等待客户机连接的功能。
3.读取字符串实现
要让服务器能读取客户机发来的一段字符串,必须设定一个基本规则:客户机可以连续输入字符给服务器,服务器循环读取,如果收到的字符串有一个回车符,则认为是一条字符串——一条消息。如果收到的字符串是“bye”,则认为客户机要结束通信,就断开客户机。
实现代码如下:
/**
* 简单Echo服务器实现
* @author www.NetJava.cn
*/
public class ChatServer {
/**
* 在指定端口上启动一个服务器
* @param port:服务器所以的端口
*/
public void setUpServer(int port){
try{
//建立绑定在指定端口上的服务器对象
java.net.ServerSocket server=new java.net.ServerSocket(port);
System.out.println("服务器创建成功!"+port);
//当有客户机连接上时,等待方法就会返回,返回一个代表与客户机连接的对象
while(true){ //让服务器进入循环等待状态
java.net.Socket client=server.accept();
System.out.println("Incoming clieng: "+client.getRemoteSocketAddress());
//调用处理连接对象的方法去处理连接对象
processChat(client);
}
}catch(Exception ef){
ef.printStackTrace();
}
}
/**
* 处理连接对象:读取客户机发来的字符串,回送给客户机
* @param client:与客户机的连接对象
*/
private void processChat(java.net.Socket client)
throws Exception{
OutputStream out=client.getOutputStream();
InputStream ins=client.getInputStream();
String s="你好,欢迎来到服务器!\r\n";
byte[] data=s.getBytes();//取得组成这个字符串的字节
out.write(data); //用输出对象发送!
out.flush();//强制输出
//调用读取字符串的方法,从输入流中读取一个字符串
String inputS=readString(ins);
while(!inputS.equals("bye")){
System.out.println("客户机说: "+inputS);
s="服务器收到:"+inputS+"\r\n";
data=s.getBytes();//取得组成这个字符串的字节数组
out.write(data); //用输出流对象发送!
out.flush();//强制输出
inputS=readString(ins); //读取客户机的下一次输入
}
s="你好,欢迎再来!\r\n";
data=s.getBytes();
out.write(data);
out.flush();
client.close();//半闭与客户机的连接
}
/**
* 从输入流对象中读取字节,拼成一个字符串返加
* 如果读到一个字节值为13,则认为以前的是一个字符串
* @param ins:输入流对象
* @return :从流上(客户机发来的)读到的字符串
*/
private String readString(InputStream ins)
throws Exception{
//创建一个字符串缓冲区
StringBuffer stb=new StringBuffer();
char c =0;
while(c!=13){
//遇到一个换行,就是一句话
int i= ins.read();//读取客户机发来的一个字节
c=(char)i;//将输入的字节转换为一个Char
stb.append(c);//将读到的一个字符加到字符串缓冲区中
}
//将读到的字节组转为字符串,并调用trim去掉尾部的空格
String inputS=stb.toString().trim();
return inputS;
}
//程序入口
public static void main(String[] args) {
ChatServer cs=new ChatServer();
cs.setUpServer(9090);
}
}
|
运行如上程序,现在,服务器可以和客户机对话了吗?如图1.14所示。
4.网络数据传送总结。
在程序中,字符串最终被以“字节”为单位通过网络发送(接收),再根据双方约定的协议 (如本例中,以回车为一条消息的结束)在程序中进行解析。这个过程如图1.15所示。
图1.15通信时,数据在网络上传送格式的分层示意图
但还有许多问题没有介绍清楚:这些字节是如何被发送到对方IP所在的电脑上的?如果中途丢了字节怎么办?这些字节又是如何转化为为电流信息的……建议大家在完成本节练习后,找一本TCP/IP分析方面的书做深入研读。
在以上代码的基础上,你可以添加上当客户端连接上服务器后,服务项器提示用户输入用户名、输入密码的功能,然后实现服务器与客户机的聊天功能。
现在最大的缺陷是:这个服务器同时只能与一个客户端通信,测试效果如图1.16所示。
当用两个telnet客户端同时连接服务器时,只有一个可以通信,前一个退出后,后一个才能通信。这就是我们下一步的任务:多线程服务器实现。
- 大小: 8.9 KB
- 大小: 63 KB
- 大小: 32.5 KB
- 大小: 60.4 KB
分享到:
相关推荐
下面将详细阐述客户端与服务器端的基本概念、工作原理以及如何实现简单的消息传递。 1. **基本概念**: - **客户端**:客户端是用户操作的设备或程序,负责发起请求,通常执行用户界面功能,如输入、显示和交互。 ...
为了实现客户端的直接读写数据库功能,服务器端通常会提供一套API或者Web服务,客户端通过调用这些接口来执行数据库操作。这种方式的优点是客户端只需关心业务逻辑,无需关注底层数据库的细节,同时也保证了数据的...
在Java中实现RTP服务器端涉及到多个关键知识点,包括网络编程、多线程、数据编码解码以及媒体处理等。下面将详细阐述这些内容。 1. **RTP协议理解**:RTP主要由两部分组成——RTP头和有效载荷。RTP头包含了时间戳、...
要实现一个FTP服务器端,我们需要理解FTP的工作原理、协议流程,并选择或编写合适的服务器软件。以下是对FTP服务器端实现的详细说明: 1. FTP工作原理: FTP基于TCP/IP协议族,使用两个并行的连接来传输数据:控制...
在本项目中,"MINA_Server_Test"是一个实现了MINA服务器端功能的可运行示例。 首先,我们来详细了解一下MINA的核心概念和架构: 1. **异步事件驱动**:MINA采用非阻塞I/O模型,即NIO(New IO)模式,通过Selector...
基于C++实现的dlt634.5104协议解析源码服务器端,对于理解该协议的内部工作原理以及开发相关的应用软件具有重要意义。 在C++中实现DLT634.5104协议解析器,首先需要理解协议的基本结构。104协议定义了报文的格式,...
本篇将深入探讨如何使用Java实现TCP客户端和服务器端的程序。 首先,我们要理解TCP连接的建立过程,通常被称为三次握手。在Java中,我们使用`java.net.Socket`类来创建客户端,`java.net.ServerSocket`类来创建...
通过以上步骤,你已经在自己的计算机上成功建立了Git服务器端,使用Gitblit作为管理工具,实现了远程代码仓库的功能。现在,团队成员可以方便地进行代码版本控制和协同开发。记住,持续学习和实践是提升Git技能的...
在服务器端,JSON主要用于数据传输,因为它结构清晰,易于读写,并且被大多数编程语言支持。例如,在服务器上,我们可能使用PHP、Python、Java或Node.js等语言来处理HTTP请求,并将处理后的数据以JSON格式响应给前端...
这需要服务器端维护一个客户端列表,并遍历这个列表将消息发送给每个客户端。 5. **用户界面(UI)**:聊天室的用户界面可能是基于控制台的简单文本交互,也可能包含图形用户界面(GUI),如使用Java的Swing或...
本篇文章将详细探讨Socket编程中客户端与服务器端的信息互通,并提供相关的客户端(CliectTest)和服务器端(ServerTest)代码示例。 ### 一、Socket编程概念 Socket,又称为“套接字”,是网络通信中的一个抽象...
2. 在服务器端调用MB_SERVER指令,确保该指令支持MODBUS功能码23,以处理读写保持寄存器的请求。 步骤4:程序测试 1. 下载并运行PLC程序,设定读取的服务器保持性寄存器起始地址为"0",长度为"5",写入的起始地址...
本篇文章将聚焦于如何使用Java来实现多客户端与服务器端的TCP通信。 首先,我们需要理解TCP通信的基本原理。TCP提供了一种点对点的、全双工的数据通信方式,通过三次握手建立连接,然后进行数据传输,最后通过四次...
4. 服务器端通过选择器监控到可读事件,从SocketChannel读取缓冲区数据,解析出消息内容。 5. 如果服务器需要向客户端发送消息,过程类似,只是方向相反,服务器将消息写入缓冲区,然后通过SocketChannel的`write()`...
2. **创建输入/输出流**:与服务器端类似,客户端也需要`DataInputStream`和`DataOutputStream`来读写数据。 3. **接收文件名和长度**:从服务器接收文件名和长度,这通常涉及到`dis.readUTF()`和`dis.readLong()` ...
本示例中,我们将探讨如何使用C#语言来实现客户端和服务器端的交互,以便它们可以相互发送消息。这一过程涉及到C#的网络编程,特别是TcpClient和TcpServer类的使用。 首先,客户端(Client)的部分主要负责发起连接...
- `ServerType`:服务器端读写信息的类型,如异步读写信息(`stThreadBlocking`)。 - `ThreadCacheSize`:客户端的最大连接数,默认值为10。 ##### ClientSocket组件 ClientSocket组件是客户端的主要组件,用于...
《冒险岛服务器端源代码解析》 冒险岛,一款经典的2D横版网络游戏,自发布以来就深受玩家喜爱。其背后的服务器端源代码是整个游戏运行的核心,它负责处理玩家的交互、游戏逻辑、数据存储等多个关键环节。下面,我们...
NTP 网络授时系统设计与实现 - NTP 服务器端授时服务软件设计与实现参考 本资源摘要信息主要介绍 NTP 网络授时系统设计与实现中的 NTP 服务器端授时服务软件设计与实现相关知识点。该系统主要包括三个功能模块:...