① java socket 、while(){} 循环后不执行下面的语句...
因为你这个式socket编程,输入流肯定是从客户端得到的,此时虽然已将客户端传过来的数据读取完毕,但服务端仍旧在运行,监听客户端的状态,并等待客户端再次发开数据,所以输入流此时并没有关闭,程序此时处于等待状态,while循环并没有跳出!所以后边的输出语句就不会执行到!
② java socket 如何发送一个结构体消息,java中结构体是个什么概念...
有一个socket 程序,一端是c++写的socket 服务程序
另一端是Java写客户端程序,两者之间需要通信。
c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组。
解决方法:c++/c socket 在发送结构体的时候其实发送的也是字节流。因为结构体本身也是内存中的一块连续数据。问题就变成了如何把结构体手动转成字节的问题了
采用类似的报头:
// packet head
typedef struct tagPacketHead{
long PacketID;
long PacketLen;
}PacketHead;此时套接口的读写方式为先读报头,在报头中取出数据负载的长度,然后再读相应字节的数据。
包头后面跟上包体,其中包体的长度,就是上面结构体中的PacketLen,Clinet首先接受包头,因为包头是两边约定好的,所以可以直接Receive一个定长的消息,也就是这个包头的长度的消息,从包头中取得包体的长度后,就可以再次Receive一个包体长度的消息了。那么Java中如何发送一个结构体呢?下面是解决方法:
使用C/S模式,Client为VC6开发,Server为Java,通过Socket通信。
package org.charry.org;
import java.net.*;
/**
*
* 字节转换,参考网络文章
*/
class Packet {
private byte[] buf = null;
/**
* 将int转为低字节在前,高字节在后的byte数组
*/
private static byte[] toLH(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将float转为低字节在前,高字节在后的byte数组
*/
private static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}
/**
* 构造并转换
*/
public Packet(int packetID, int packetLen, String packetBody) {
byte[] temp = null;
buf = new byte[packetBody.getBytes().length + 8];
temp = toLH(packetID);
System.array(temp, 0, buf, 0, temp.length);
temp = toLH(packetLen);
System.array(temp, 0, buf, 4, temp.length);
System.array(packetBody.getBytes(), 0, buf, 8, packetBody.length());
}
/**
* 返回要发送的数组
*/
public byte[] getBuf() {
return buf;
}
/**
* 发送测试
*/
public static void main(String[] args) {
try {
String tmp = “test string!”;
Socket sock = new Socket(”127.0.0.1″, 8888);
sock.getOutputStream().write(
new Packet(123, tmp.length(), tmp).getBuf());
sock.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果需要用Java 接收结构体的话只需要将上面过程逆过来即可。
③ 使用Java 1用socket程序发送和接收字节数组 2用十六进制的形式显示每个字节里面的内容
我们定义发送者和接收者,发送者作为客户端,接收者作为服务端。
Sender.java
importjava.io.DataOutputStream;
importjava.io.IOException;
importjava.net.Socket;
importjava.util.Arrays;
publicclassSender{
in(String[]args)throwsException{
//127.0.0.1代表本机地址,在8888端口上监听
Sendersender=newSender("127.0.0.1",8888);
byte[]bytes={15,16,17,120};//对应的十六进制是0F101178
sender.send(bytes);
System.out.println("发送"+Arrays.toString(bytes)+"完毕!");
}
privatefinalStringhost;
privatefinalintport;
publicSender(Stringhost,intport){
this.host=host;
this.port=port;
}
privatevoidsend(byte[]bytes)throwsIOException{
Socketsocket=newSocket(host,port);//建立和服务端的socket
try(DataOutputStreamdos//建立输出流
=newDataOutputStream(socket.getOutputStream())){
dos.write(bytes,0,bytes.length);//向输出流写入bytes
}
}
}
Receiver.java
importjava.io.DataInputStream;
importjava.io.IOException;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassReceiver{
publicstaticvoidmain(String[]args)throwsException{
Receiverreceiver=newReceiver(8888);
receiver.receive();
}
;
publicReceiver(intport)throwsIOException{
serverSocket=newServerSocket(port);
}
privatevoidreceive()throwsIOException{
System.out.println("等待客户端连接...");
Socketsocket=serverSocket.accept();
try(DataInputStreamdis=newDataInputStream(socket.getInputStream())){
byte[]bytes=newbyte[1024];//假设发送的字节数不超过1024个
intsize=dis.read(bytes);//size是读取到的字节数
Stringhex=bytesToHex(bytes,0,size);
System.out.println("接收到的byte数组的十六进制:"+hex);
}
}
/**
*将byte数组转化为十六进制字符串
*
*@parambytesbyte[]数组
*@parambegin起始位置
*@paramend结束位置
*@returnbyte数组的十六进制字符串表示
*/
privateStringbytesToHex(byte[]bytes,intbegin,intend){
StringBuilderhexBuilder=newStringBuilder(2*(end-begin));
for(inti=begin;i<end;i++){
hexBuilder.append(Character.forDigit((bytes[i]&0xF0)>>4,16));//转化高四位
hexBuilder.append(Character.forDigit((bytes[i]&0x0F),16));//转化低四位
hexBuilder.append('');//加一个空格将每个字节分隔开
}
returnhexBuilder.toString().toUpperCase();
}
}
运行,首先启动服务端:
④ java socket输入流inputStream.read(byte[])方法一次读入多帧数据,也就是多帧数据连在一起
因为inputStream.read(byte)是尽可抄能的读byte[]大小的数据袭,当你的服务端发送数据速度大于客户端读取数据的速度时,就会出现客户端读到多帧连在一起的报文。而这些发送数据,读取数据的速度是未知的。所以我们需要人为的来做一些调整。比如说每一帧作为一行写入Socket,客户端每次从socket读取一行。这样客户端每次都是读取一帧。
以上情况可以这样实现:在服务端使用PrintWriter
PrintWriterwriter=newPrintWriter(socket.getOutputStream());
writer.println(data);
客户端可以使用BufferedReader
BufferedReaderreader=newBufferedReader(newBufferedInputStream(socket.getInputStream()));
Strings=reader.readLine();
⑤ java的socket流的read问题
HTTP协议是有固定格式的,由Header + Body组成,你可以先去看看相关协议说明。
读取时应该先通过连续2个换行符分割header和body,然后在header里查Content-Length,根据ContentLength才知道body到底有多长,这样你才能从流中把一个个http包分割出来。
对于chunk模式,在最后会有一个长度为0的chunk标识,来指示响应已结束。
⑥ java服务器端用传输给客户端文件流(fileinputstream),客户端应该如何接收(socket )
其实这个问题你应该先想一下socket到底是一个什么东西,在网络编程中socket到底用来做什么的。socket:在操作系统内核中它代表网络连接的一个端点(endpoint),在应用程序中它代表一个打开的文件。socketpair唯一确定的一条网络连接,socketpair就是客户端socket和服务端socket的一个组合。也就是客户端ip和port与服务端ip和port的组合。一条网络连接也就是一条通信的信道,tcp连接代表的信道是全双工的。以信道来讲,逻辑上就存在两个管道来代表输出与输入来发送和接收信息。
那么在应用程序上我们就可以拿到这2个管道来完成socket之间的通信。
以你的应用来看输出流fos就代表着图中的红色管道,那么在服务端就应该是这个样的。
ScoketconnSock=serverSocket.accept();//connSock代表着服务端的Socket
InputStreamis=connSock.getInputStream();//输入流is代表图中的红色管道
OutputStreaos=connSock.getOutputStream();//输出流os代表图中的绿色管道
在服务端有一个字节缓冲区来存放从is读取的字节数据
byte[]buffer=newbyte[1024];
然后服务端读取数据来填充这个字节缓冲区
is.read(buffer);//比如这样
然后就根据你的需求来操作这个buffer了。
然后把处理过后的数据通过os发送给客户端。os就是图中的那个绿色管道
os.write(处理过后的数据);
⑦ java-socket 如何判断网络传过来的是字符串还是对象
socket建立连接的getInputstream()和getOutputStream()方法都是字节流。
可以通过writeUTF等方法来进行写入。
如果想判断是字符串还是对象,你可以对对象进行一下处理。这个对象是某个类的实例,这个类里面定义一个标识属性,比如public int flag,通过字节流进行交流后,这边读取到,首先读取一个int数据,如果是1或者是你令的别的标志,那么就是对象,按对象处理。如果readInt后不能转化为你要求的那个标识,那么就是字符串。用public boolean flag等也可。
都是字节流过来的,读取规定字节数看看是不是你事先定好的标志。