A. 在java中实现TCP协议编程中怎么传
在Java中实现TCP协议编程
ServerSocket:编写TCP网络服务程序,首先要用到java.net.ServerSocket类用以创建服务器Socket
构造方法:
ServerSocket(intport):创建绑定到特定端口的服务器套接字
ServerSocket(intport,intbacklog):利用指定的backlog(服务器忙时保持连接请求的等待客户数量),创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(intport,intbacklog,InetAddressbindAddr):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。
Socket:客户端要与服务器建立连接,必须先创建一个Socket对象
常用构造方法
Socket(Stringhost,intport):创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(InetAddressaddress,intport):创建一个流套接字并将其连接到指定IP地址的指定端口号。
服务器端程序调用ServerSocket类中的accept()方法等待客户端的连接请求,一旦accept()接收了客户端连接请求,该方法返回一个与该客户端建立了专线连接的Socket对象,不用程序去创建这个Socket对象。建立了连接的两个Socket是以IO流的方式进行数据交换的,Java提供了Socket类中的getInputStream()返回Socket的输入流对象,getOutputStream()返回Socket的输出流对象。
TCP服务器与TCP客户端间的数据的接受图示:
用TCP实现服务器与客户端的“聊天”:
实例代码:
客户端:
packagecom.hbsi.net;
importjava.net.Socket;
importjava.io.*;
publicclassTcpClient{
publicstaticvoidmain(String[]args)throwsException{
//1.建立tcp客户端socket,要确定要连接的服务器ip,port
Sockets=newSocket("192.168.49.87",9009);
//获取键盘录入
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
//2.通过建立的socket,获取输出流对象
//数据输出给服务器端
OutputStreamout=s.getOutputStream();
BufferedWriterbwout=newBufferedWriter(newOutputStreamWriter(out));
//获取服务器端返回的数据
//读取服务器端发过来的信息InputStreamReader()
BufferedReaderbrin=newBufferedReader(newInputStreamReader(
s.getInputStream()));
Stringline=null;
while((line=br.readLine())!=null){
if(line.equals("over"))
break;
bwout.write(line);
bwout.newLine();
bwout.flush();
Stringstr=brin.readLine();
System.out.println("server:"+str);
}
br.close();
s.close();
}
}
服务器端:
packagecom.hbsi.net;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStreamWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassTcpServer{
publicstaticvoidmain(String[]args)throwsException{
//1.建立服务器socket
ServerSocketss=newServerSocket(9009);
//2.调用accept()
Sockets=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()
+"...connection");
//读取客户的信息的输入流
InputStreamin=s.getInputStream();
BufferedReaderbrin=newBufferedReader(newInputStreamReader(in));
//向客户端发送信息输出流,服务端向客户端返回信息OutputStreamWriter()
BufferedWriterbrout=newBufferedWriter(newOutputStreamWriter(
s.getOutputStream())); Stringline=null;
while((line=brin.readLine())!=null){
System.out.println("client:"+line);
brout.write(line.toUpperCase());//服务器端收到信息后,将信息转为大写返回给客户端toUpperCase()
brout.newLine();
brout.flush();
}
s.close();
ss.close();
}
}
B. TCP/IP协议 怎么用JAVA发送和接收二进制数据 要具体实例
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 delimiter public 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/O public 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; } }
C. android或java 用jnetpcap可以发送icmp报文吗
你可以用socket编程,java socket是封装了TCP协议的,不需要你去设置里面的一些参数了。 你还可以用java jpcap编写,这个可以发送接收arp,tcp,udp,icmp等各种报文
D. 请教大神,java socket接口,TCP长连接,怎么解析和发送一种协议格式数据包
建议你下载我的java版本至尊聊天程序源码下去参考。在CSDN或网络上找吧。
协议完全回自己来定制,答数据以字节发送,以什么开始,什么结束,中间分几段,都可由你自己来定,接收时,就按你定的规则来解析并还原。比如:我要的协议格式为
:>10:3:5:content:<
:>表示一条消息的开始。
10表示总消息长度(只是个代数,有可能不是10,需要你在发送前计算)
:为分隔符
3为头消息长度,也可能不是3
5表示后面的消息内容长度,甚至还可以定制,是否有图片,从多少位置开始是图片的数据。
:<表示结束标志
没有人限制你的协议。
关键一点:你在收取的时候,一定要注意数据可能会粘包,这个问题很头疼的。因为一般都是多线程模式。这需要你自己来处理它。一言难清。可以参考我的聊天程序。
E. java中的socket编程是作什么的
Socket,又称为套接字,是计算机网络通信的基本技术之一。如今,大多数基于网络的软件,如浏览器、即时通讯工具甚至是P2P下载,都是基于Socket实现的。本文将介绍基于TCP/IP的Socket编程,并展示如何编写客户端和服务器程序。
在接下来的示例中,我们将使用基于TCP/IP协议的Socket编程,因为这个协议在实际应用中比UDP/IP更为广泛。所有与Socket相关的类都位于java.net包下,因此在进行Socket编程时需要引入这个包。
接下来是写入数据的过程。客户端的Socket对象可以得到一个OutputStream对象,然后可以通过这个对象写入数据,类似于文件输入输出的处理代码。
打开服务器端的Socket也很简单。通过Socket对象,可以获取一个InputStream对象,然后像处理文件输入输出一样读取数据。这里我们将读取的数据打印出来。
使用Socket实现一个回声服务器的功能,就是服务器会将客户端发送过来的数据传回给客户端。具体实现时,服务器端会监听特定的端口,当有客户端连接时,服务器会接收客户端发送的数据,并将这些数据原样返回给客户端。
客户端则需要知道服务器的IP地址和端口号,然后通过Socket对象建立与服务器的连接。客户端发送数据后,会等待服务器的响应,服务器接收到数据后,会将数据返回给客户端。客户端接收到返回的数据后,就可以处理这些数据了。
Socket编程是构建网络应用的重要基础,通过上述示例,我们可以看到Socket的使用并不复杂。只要掌握了基本的Socket编程方法,就可以开发出各种基于网络的应用程序。
F. Java面试之TCP的粘包和拆包
Java面试之TCP的粘包和拆包
在TCP协议中,数据的发送和接收都是以流的形式进行的,而发送的数据是以数据包的形式封装的。然而,接收方并不能确定每次读取到的数据包大小,因此会出现TCP粘包和拆包问题。
一、TCP粘包和拆包的概念
二、造成粘包和拆包的原因
造成粘包现象的原因:
造成拆包现象的原因:
三、解决TCP粘包和拆包问题的方法
定长消息
原理:发送方每次发送固定长度的数据,接收方按照固定长度进行接收和处理。
优点:实现简单,易于理解。
缺点:灵活性差,不适用于数据长度变化较大的场景。
特定字符分割消息
原理:发送方在每个数据包后面加上特定的字符(例如“rn”),接收方以该字符为标志进行数据拆分。
优点:实现相对简单,适用于文本数据的传输。
缺点:特定字符可能与数据内容冲突,导致数据解析错误。
将消息分为消息头和消息体
原理:消息头记录消息的长度等信息,接收方先接收消息头,然后根据消息头中的长度信息接收消息体。
优点:灵活性好,适用于数据长度变化较大的场景。
缺点:需要额外的空间来存储消息头信息。
使用消息结束符
原理:发送方在每个数据包的末尾添加一个特定的消息结束符(例如“0”),接收方接收到消息结束符时,就认为一条消息接收完成。
优点:实现简单,易于理解。
缺点:消息结束符可能与数据内容冲突,导致数据解析错误;同时,如果数据中包含大量零值字节,可能会增加解析的复杂性。
利用应用层协议
原理:在应用层协议中定义数据包的格式和长度信息,如HTTP协议中的Content-Length字段。接收方在接收数据时,根据应用层协议中的长度信息来精确地读取整个数据。
优点:标准化、规范化,易于实现和维护。
缺点:需要额外的协议开销,可能增加数据传输的复杂性。
综上所述,TCP粘包和拆包问题是网络编程中常见的问题,需要根据具体的应用场景选择合适的解决方法。在实际开发中,可以结合多种方法来解决粘包和拆包问题,以提高数据传输的可靠性和准确性。