java中怎么用TCP发送数据?

Python015

java中怎么用TCP发送数据?,第1张

println和 print的区别 还是参照javadoc比较准确,就是最后是否跟上一个换行。这种函数含义的解释,查手册是最准确的。

s.getOutputStream() 返回的结果 直接就是 OutputStream 这个类本身就是用于发送 byte[]的。

字符串转化成 byte[] 直接调用getBytes。

LZ应该详细阅读java手册。对于已经接触到的类 比如String,这种基本的,要看看它所有的函数实现。这就和学英语背单词一样,必须要有量的上去才行。

以下是一个展示java使用tcp通讯的简单例子,包括服务器和客户端代码:

/**

*TCPServer

*/

import java.io.*

import java.net.*

class TCPServer{

public static void main(String[] args)throws IOException{

ServerSocket listen = new ServerSocket(5050)

Socket server = listen.accept()

InputStream in = server.getInputStream()

OutputStream out = server.getOutputStream()

char c = (char)in.read()

System.out.println("收到:" + c)

out.write('s')

out.close()

in.close()

server.close()

listen.close()

}

}

/**

*TCPClient

*/

import java.io.*

import java.net.*

class TCPClient{

public static void main(String[] args)throws IOException{

Socket client = new Socket("127.0.0.1" , 5050)

InputStream in = client.getInputStream()

OutputStream out = client.getOutputStream()

out.write('c')

char c = (char)in.read()

System.out.println("收到:" + c)

out.close()

in.close()

client.close()

}

}

1.TCP/IP协议要求信息必须在块(chunk)中发送和接收,而块的长度必须是8位的倍数,因此,我们可以认为TCP/IP协议中传输的信息是字节序列。如何发送和解析信息需要一定的应用程序协议。

2.信息编码:

首先是Java里对基本整型的处理,发送时,要注意:1)每种数据类型的字节个数;2)这些字节的发送顺序是怎样的?(little-endian还是

big-endian);3)所传输的数值是有符号的(signed)还是无符号的(unsigned)。具体编码时采用位操作(移位和屏蔽)就可以了。

具体在Java里,可以采用DataOutputStream类和ByteArrayOutputStream来实现。恢复时可以采用

DataInputStream类和ByteArrayInputStream类。

其次,字符串和文本,在一组符号与一组整数之间的映射称为编码字符集(coded character

set)。发送者与接收者必须在符号与整数的映射方式上达成共识,才能使用文本信息进行通信,最简单的方法就是定义一个标准字符集。具体编码时采用

String的getBytes()方法。

最后,位操作。如果设置一个特定的设为1,先设置好掩码(mask),之后用或操作;要清空特定一位,用与操作。

3.成帧与解析

成帧(framing)技术解决了接收端如何定位消息的首位位置的问题。

如果接收者试图从套接字中读取比消息本身更多的字节,将可能发生以下两种情况之一:如果信道中没有其他消息,接收者将阻塞等待,同时无法处理接收

到的消息;如果发送者也在等待接收端的响应消息,则会形成死锁(dealock);另一方面,如果信道中还有其他消息,则接收者会将后面消息的一部分甚至

全部读到第一条消息中去,这将产生一些协议错误。因此,在使用TCP套接字时,成帧就是一个非常重要的考虑因素。

有两个技术:

1.基于定界符(Delimiter-based):消息的结束由一个唯一的标记(unique

marker)指出,即发送者在传输完数据后显式添加的一个特殊字节序列。这个特殊标记不能在传输的数据中出现。幸运的是,填充(stuffing)技术

能够对消息中出现的定界符进行修改,从而使接收者不将其识别为定界符。在接收者扫描定界符时,还能识别出修改过的数据,并在输出消息中对其进行还原,从而

使其与原始消息一致。

2.显式长度(Explicit length):在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。这种方法要确定消息长度的上限,以确定保存这个长度需要的字节数。

接口:

Java代码 import java.io.IOException import java.io.OutputStream public interface Framer { void frameMsg(byte [] message,OutputStream out) throws IOException byte [] nextMsg() throws IOException }

定界符的方式:

Java代码 import java.io.ByteArrayOutputStream import java.io.EOFException import java.io.IOException import java.io.InputStream import java.io.OutputStream public class DelimFramer implements Framer { private InputStream in//data source private static final byte DELIMTER=(byte)'\n'//message delimiterpublic DelimFramer(InputStream in){ this.in=in }@Override public void frameMsg(byte[] message, OutputStream out) throws IOException { //ensure that the message dose not contain the delimiter for(byte b:message){ if(b==DELIMTER) throw new IOException("Message contains delimiter") } out.write(message) out.write(DELIMTER) out.flush() }@Override public byte[] nextMsg() throws IOException { ByteArrayOutputStream messageBuffer=new ByteArrayOutputStream() int nextByte while((nextByte=in.read())!=DELIMTER){ if(nextByte==-1){//end of stream? if(messageBuffer.size()==0){ return null }else{ throw new EOFException("Non-empty message without delimiter") } } messageBuffer.write(nextByte) } return messageBuffer.toByteArray() } }

显式长度方法:

Java代码 import java.io.DataInputStream import java.io.EOFException import java.io.IOException import java.io.InputStream import java.io.OutputStream public class LengthFramer implements Framer { public static final int MAXMESSAGELENGTH=65535 public static final int BYTEMASK=0xff public static final int SHOTMASK=0xffff public static final int BYTESHIFT=8 private DataInputStream in// wrapper for data I/Opublic LengthFramer(InputStream in) throws IOException{ this.in=new DataInputStream(in) }@Override public void frameMsg(byte[] message, OutputStream out) throws IOException { if(message.length>MAXMESSAGELENGTH){ throw new IOException("message too long") }//write length prefix out.write((message.length>>BYTEMASK)&BYTEMASK) out.write(message.length&BYTEMASK) //write message out.write(message) out.flush() }@Override public byte[] nextMsg() throws IOException { int length try{ length=in.readUnsignedShort() }catch(EOFException e){ //no (or 1 byte) message return null } //0<=length<=65535 byte [] msg=new byte[length] in.readFully(msg)//if exception,it's a framing error return msg } }