程序功能:
从Client发送一个字符串到Server, Server获取到消息后打印出来,然后返回一个字符串给Client端。
Client读取Server返回的字符串。我写了一个例子,但是运行不成功。 麻烦找出错误,或写一个例子给我。package com.zf.test05;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class Client { public static void main(String[] args) throws Exception {
final String message = "client message";
Socket socket = new Socket("127.0.0.1" , 8888);
InputStream is = socket.getInputStream() ;
OutputStream os = socket.getOutputStream() ;
//send msg
os.write(message.getBytes());
os.flush();
System.out.println("client:send message success!");
// receive msg
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
byte[] buf = new byte[1024];
int len = -1;
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
}
byte[] receiveDatas = baos.toByteArray() ;
System.out.printf("client:message:%s%n" ,
new String(receiveDatas));
socket.close();
}
}package com.zf.test05;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {
public static void main(String[] args) throws Exception {
final String message = "server message";
ServerSocket serverSocket = new ServerSocket(8888) ;
System.out.println("server start success...");
Socket client = serverSocket.accept(); InputStream is = client.getInputStream() ;
OutputStream os = client.getOutputStream() ; // receive msg
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
byte[] buf = new byte[1024];
int len = -1;
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
baos.flush();
} byte[] receiveDatas = baos.toByteArray() ; System.out.printf("server:message:%s%n"
,new String(receiveDatas));
//send msg
os.write(message.getBytes());
os.flush();
System.out.println("server:send message success...");
client.close();
serverSocket.close();
}}
从Client发送一个字符串到Server, Server获取到消息后打印出来,然后返回一个字符串给Client端。
Client读取Server返回的字符串。我写了一个例子,但是运行不成功。 麻烦找出错误,或写一个例子给我。package com.zf.test05;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class Client { public static void main(String[] args) throws Exception {
final String message = "client message";
Socket socket = new Socket("127.0.0.1" , 8888);
InputStream is = socket.getInputStream() ;
OutputStream os = socket.getOutputStream() ;
//send msg
os.write(message.getBytes());
os.flush();
System.out.println("client:send message success!");
// receive msg
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
byte[] buf = new byte[1024];
int len = -1;
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
}
byte[] receiveDatas = baos.toByteArray() ;
System.out.printf("client:message:%s%n" ,
new String(receiveDatas));
socket.close();
}
}package com.zf.test05;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {
public static void main(String[] args) throws Exception {
final String message = "server message";
ServerSocket serverSocket = new ServerSocket(8888) ;
System.out.println("server start success...");
Socket client = serverSocket.accept(); InputStream is = client.getInputStream() ;
OutputStream os = client.getOutputStream() ; // receive msg
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
byte[] buf = new byte[1024];
int len = -1;
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
baos.flush();
} byte[] receiveDatas = baos.toByteArray() ; System.out.printf("server:message:%s%n"
,new String(receiveDatas));
//send msg
os.write(message.getBytes());
os.flush();
System.out.println("server:send message success...");
client.close();
serverSocket.close();
}}
解决方案 »
- java困惑
- java 线程start后即使运行结束也不能再start了?
- jdbc 连接sql2000提示java.lang.classnotfoundexception: com.microsoft.jdbc.sqlserver.
- 如何在打包时把log4j配置文件排除在外?
- java hibernate中如何得到前十条数据
- 请教一个关于MSSQLSERVER的问题:
- Drools&Spring集成之后,怎么在DRL规则文件LHS和RHS部分调用DAO方法?
- @@@@@@@@@@@@@@@@@up有分!!
- Java 新手弱弱的问
- java使用jacob调控件出现的异常
- 新浪面试题 java实现以及分析? 求助
- byte a = 'A';这样写对不对?
(len = is.read(buf)) != -1
byte[] buf = new byte[1024];
int len = -1;
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
}
改为
byte[] buf = new byte[1024];
int len = is.read();
baos.write(buf , 0 , len);
试一下
这样是不行的。
int len = is.read();
is.read(); 只读了一个字节, len是这一个字节的指 ,并不是读取的length
后面就不能用
baos.write(buf , 0 , len);了
个人愚见:我认为这两个while是没法跳出循环的,在socket未关闭之前,inputStream会一直尝试读取socket中的数据
InputStream is = client.getInputStream();//更换下顺序
OutputStream os = client.getOutputStream();
变成
OutputStream os = client.getOutputStream() ;
InputStream is = client.getInputStream() ;
这样是不行的。
int len = is.read();
is.read(); 只读了一个字节, len是这一个字节的指 ,并不是读取的length
后面就不能用
baos.write(buf , 0 , len);了is.read()是一个字节一个字节的读,并不是读一个字节吧
蹭1分,多个java版裤衩。
我把Client段改成
Socket socket = new Socket("127.0.0.1" , 8888);
OutputStream os = socket.getOutputStream() ;
InputStream is = socket.getInputStream() ;
还是在下面这一步阻塞
while((len = is.read(buf)) != -1)
这样是不行的。
int len = is.read();
is.read(); 只读了一个字节, len是这一个字节的指 ,并不是读取的length
后面就不能用
baos.write(buf , 0 , len);了is.read()是一个字节一个字节的读,并不是读一个字节吧read()方法调用一次,只读取一个字节。 如果需要把内容读完,就要循环的调用read()方法。
read()方法的返回值是读取的这个字节的值。
read(byte[])方法读取指定最大长度的字节。返回值是读取的长度。
我把Client段改成
Socket socket = new Socket("127.0.0.1" , 8888);
OutputStream os = socket.getOutputStream() ;
InputStream is = socket.getInputStream() ;
还是在下面这一步阻塞
while((len = is.read(buf)) != -1)
读写应该在不同的线程中进行。如果你非要写单线程,那读写都要在循环中进行。不然你就一直死在循环里了
发送和接收消息使用DataOutputStream 与 DataInputStream
现在的思路是
发送时:先将消息的长度使用short类型发送 然后接着发送消息内容
接收时:先读取一个short类型的数据,然后创建指定大小的byte数组,然后用readFull()方法一次性将数组填满。
现在测试是成功了。package com.zf.test05;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class Client02 { public static void main(String[] args) throws Exception {
final String message = "client message";
Socket socket = new Socket("127.0.0.1" , 8888);
InputStream is = socket.getInputStream() ;
OutputStream os = socket.getOutputStream() ;
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
//send msg
dos.writeShort(message.length()); //write msg length
dos.write(message.getBytes()); // write msg content
dos.flush();
System.out.println("client:send message success!");
// receive msg
int length = dis.readShort(); //read msg length
byte[] receiveDatas = new byte[length];
dis.readFully(receiveDatas); //read full message
System.out.printf("client:message:%s%n" ,
new String(receiveDatas));
socket.close();
}
}
package com.zf.test05;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server02 {
public static void main(String[] args) throws Exception { final String message = "server message"; ServerSocket serverSocket = new ServerSocket(8888) ; System.out.println("server start success..."); Socket client = serverSocket.accept(); InputStream is = client.getInputStream() ;
OutputStream os = client.getOutputStream() ;
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os); // receive msg
int length = dis.readShort(); //read msg length
byte[] receiveDatas = new byte[length];
dis.readFully(receiveDatas); //read full message System.out.printf("server:message:%s%n"
,new String(receiveDatas));
//send msg
dos.writeShort(message.length()); //write msg length
dos.write(message.getBytes()); // write msg content
dos.flush();
System.out.println("server:send message success..."); client.close();
serverSocket.close();
}}
这样是不行的。
int len = is.read();
is.read(); 只读了一个字节, len是这一个字节的指 ,并不是读取的length
后面就不能用
baos.write(buf , 0 , len);了is.read()是一个字节一个字节的读,并不是读一个字节吧read()方法调用一次,只读取一个字节。 如果需要把内容读完,就要循环的调用read()方法。
read()方法的返回值是读取的这个字节的值。
read(byte[])方法读取指定最大长度的字节。返回值是读取的长度。
刚查了一下文档,本人确实错了!刚测试了下
将is.read();改为is.read(buf)也能实现其功能。
我用了16楼所示的方式之后 测试成功。没有出现阻塞的情况了。
Client与Server都是先开InputStream再开OutputStream。
可能不是跟开流的顺序由关吧。我调试的时候程序不是在getInputStream() ;或getOutputStream() ;时阻塞。
而是在while((len = is.read(buf)) != -1)时阻塞。
不清楚为什么会这样。
这样是不行的。
int len = is.read();
is.read(); 只读了一个字节, len是这一个字节的指 ,并不是读取的length
后面就不能用
baos.write(buf , 0 , len);了is.read()是一个字节一个字节的读,并不是读一个字节吧read()方法调用一次,只读取一个字节。 如果需要把内容读完,就要循环的调用read()方法。
read()方法的返回值是读取的这个字节的值。
read(byte[])方法读取指定最大长度的字节。返回值是读取的长度。
刚查了一下文档,本人确实错了!刚测试了下
将is.read();改为is.read(buf)也能实现其功能。
为什么已经已经向OutputStream中写入了数据。 InputStream的read还是继续阻塞呢。
倒霉孩子 细心点么 while都写错了,那样是出不来的..
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) > 0){
baos.write(buf , 0 , len);
}
read方法一次都没返回,循环体没进去过。
倒霉孩子 细心点么 while都写错了,那样是出不来的..
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) > 0){
baos.write(buf , 0 , len);
}> 0 与 != -1 在这里都一样的。
while((len = is.read(buf)) != -1){
baos.write(buf , 0 , len);
baos.flush();
}
改成
len = is.read(buf);
if(len != -1){
baos.write(buf , 0 , len);
baos.flush();
}看看能不能出效果
倒霉孩子 细心点么 while都写错了,那样是出不来的..
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) > 0){
baos.write(buf , 0 , len);
}> 0 与 != -1 在这里都一样的。问题提的很尖锐.. 其实这只是为了避免你上班电影的buf出错的情况..
假如你一不小心把byte[] buf = new byte[1024]; 写成byte[] buf = new byte[0];你就知道作用了
倒霉孩子 细心点么 while都写错了,那样是出不来的..
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) > 0){
baos.write(buf , 0 , len);
}> 0 与 != -1 在这里都一样的。问题提的很尖锐.. 其实这只是为了避免你上班电影的buf出错的情况..
假如你一不小心把byte[] buf = new byte[1024]; 写成byte[] buf = new byte[0];你就知道作用了不好意思上边错了几个字:应该是上边定义
将while的条件改为while(is.available() > 0 && (len = is.read(buf)) != -1)
读取之前先用available()获取可读的字节数(该方法可以不阻塞的获取可读字节数),问题就解决了。分析原因就是因为is.read(buf)阻塞,如果将inputstream里面的内容读完了,再次调用read方法时,将会一直阻塞,并不是返回-1,直到与该inputstream对应的outputstream关闭才会返回-1。
可能从Socekt获取的Inputstream与FileInputStream不同,FileInputStream在读完文件后就再次读就返回-1.
但是Socekt获取的InputStream。要等另一端的OutputStream关闭它才返回-1 否则一直阻塞。
如你所料,还是有问题。
我将缓冲区该成一个字节byte[] buf = new byte[1];
结果打印的结果,只读取了一个字符。
private static AtomicInteger iID = new AtomicInteger(0); private ExecutorService iExecutor; private ServerSocketChannel iServerChannel; private boolean iRunning = false; private Thread iServerThread; private IClientHandlerFactory iClientHandlerFactory; private int iHeaderSize; private IMessageLengthParser iMessageLengthParser; private int iPort; private IServerEventListener iServerEventListener; private Logger iLogger; public TCPServer(int port, IClientHandlerFactory clientHandlerFactory, int headerSize,
IMessageLengthParser messageLengthParser, Logger logger) {
iPort = port;
iLogger = logger.getClone("TCPServer Port:" + port);
iExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "server-listener-thread-" + iID.incrementAndGet());
}
}); iClientHandlerFactory = clientHandlerFactory; iHeaderSize = headerSize;
iMessageLengthParser = messageLengthParser; try {
iServerChannel = ServerSocketChannel.open();
iServerChannel.socket().bind(new InetSocketAddress(port));
}
catch (IOException e) {
throw new RuntimeException("Cannot create simulator server");
}
} public void setServerEventListener(IServerEventListener listener) {
iServerEventListener = listener;
} public void start() {
if (iRunning)
return; iLogger.info("Starting TCP Server on port " + iPort + "..."); iRunning = true; iExecutor.execute(new Runnable() {
@Override
public void run() {
iServerThread = Thread.currentThread();
while (iRunning) {
try {
iLogger.info("Server started on port: " + iPort); SocketChannel clientChannel = iServerChannel.accept(); if (iServerEventListener != null)
iServerEventListener.onClientConnected(clientChannel); iLogger.info("Client connected to port: " + iPort);
IClientHandler clientHandler = iClientHandlerFactory.getClientHandler(clientChannel);
SocketReader reader = new SocketReader(clientHandler, clientChannel, iHeaderSize, iMessageLengthParser,
iServerEventListener, iLogger);
reader.start();
}
catch (IOException e) {
iLogger.error("Error waiting for connection", e);
if (iServerEventListener != null)
iServerEventListener.onServerDown();
break;
}
}
iLogger.info("TCP server on port " + iPort + " stopped");
}
});
} public void stop() {
iLogger.info("Stopping TCP server on port " + iPort);
iRunning = false;
if (iServerThread != null)
iServerThread.interrupt();
} private static class SocketReader implements Runnable {
private static final int INITIAL_BUFFER_SIZE = 5000; private final IServerEventListener iServerListener; private Logger iLogger; private final SocketChannel iSocketChannel; private int iHeaderSize; private IMessageLengthParser iMessageLengthParser; private ITCPConnectionListener iClientListener; private ByteBuffer iMessageBuffer = ByteBuffer.allocate(INITIAL_BUFFER_SIZE); private Thread iThread; SocketReader(ITCPConnectionListener clientListener, SocketChannel socketChannel, int headerSize,
IMessageLengthParser messageLengthParser, IServerEventListener serverListener, Logger logger) {
iClientListener = clientListener;
iSocketChannel = socketChannel;
iMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
iHeaderSize = headerSize;
iMessageLengthParser = messageLengthParser;
iThread = new Thread(this, "socket-reader-thread");
iServerListener = serverListener;
iLogger = logger;
} public void start() {
iLogger.info("Starting reader thread");
iThread.start();
} public void stop() {
try {
if (iServerListener != null)
iServerListener.onClientDisconnect(iSocketChannel);
iSocketChannel.close();
}
catch (IOException e) {
// ignore
}
iThread.interrupt();
} @Override
public void run() {
try {
while (iSocketChannel.isOpen()) {
if (iSocketChannel.read(iMessageBuffer) < 0)
throw new EOFException("Remote initiated close."); if (iMessageBuffer.position() < iHeaderSize)
continue; iMessageBuffer.flip(); int initialLimit = iMessageBuffer.limit(); int currentPos;
for (int messageCount = 0; true; messageCount++) {
iMessageBuffer.limit(initialLimit);
currentPos = iMessageBuffer.position(); // buffer left does not contain a complete packet header
if (currentPos + iHeaderSize > initialLimit)
break; int messageLength = iMessageLengthParser.parseLength(currentPos, iMessageBuffer); // Received incomplete message
if (messageLength + currentPos > initialLimit) {
// buffer not big enough to hold a complete message
if (messageCount == 0 && messageLength + currentPos > iMessageBuffer.capacity()) {
ByteBuffer doubleSizedBuffer = ByteBuffer.allocate(iMessageBuffer.capacity() * 2);
doubleSizedBuffer.order(ByteOrder.LITTLE_ENDIAN);
iMessageBuffer.flip();
doubleSizedBuffer.put(iMessageBuffer);
iMessageBuffer = doubleSizedBuffer;
}
break;
} if (messageLength == 0) {
iLogger.error(SimulatorUtils.toHex(iMessageBuffer));
} iMessageBuffer.limit(currentPos + messageLength); try {
iClientListener.onMessage(iMessageBuffer);
}
catch (Exception e) {
iLogger.error("Listener thrown unhandled exception.", e);
iMessageBuffer.clear();
}
iMessageBuffer.position(currentPos + messageLength);
} iMessageBuffer.limit(initialLimit);
iMessageBuffer.compact();
}
}
catch (IOException e) {
iLogger.info("Client disconnection");
iMessageBuffer.clear();
stop();
}
}
}
}这是一个实际中使用的TCPServer范例。这个服务器对于每一个客户连接都开一条线程,通过ITCPConnectionListener来与外界交流。
public interface ITCPConnectionListener {
void onMessage(ByteBuffer buffer); void onClose(); void onUnexpectedClose();}
这里对于消息的假设是,客户端给服务器发送的消息都有一个消息头,消息头里面定义了这个消息的长度,由IMessageLengthParser来取得。而消息头的长度必须固定,仔细看构造函数的参数。
public interface IMessageLengthParser {
int parseLength(int offset, ByteBuffer buffer);
}这些都在构造函数里面传入。如果你花两天时间把这段代码研究透彻,你就升级了。