网络通信 第二节
自己实现一个客户端
InputStream与OutputStream
InputStream
- InputStream 为字节输入流,它本身为一个抽象类,必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类。 继承自InputStream 的流都是向程序中输入数据的,且数据单位为字节(8bit)
- InputStream是输入字节数据用的类,所以InputStream类提供了3种重载的read方法Inputstream类中的常用方法:
- public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
- public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
- public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
注意第一个read是读取,而下面两个read却是将读取的数据放入数组
OutputStream
- public void write(byte b[ ]):将参数b中的字节写到输出流。
- public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
- public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
- public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
- public void close( ) : 关闭输出流并释放与流相关的系统资源。
原文链接:https://blog.csdn.net/hguisu/article/details/7418161
服务端与客户端的socket
服务端socket
ServerSocket serversocket=new ServerSocket (8888);
Socket clientsocket=serversocket.accept();
客户端socket
Socket socket=new Socket("127.0.0.1",8888);//(服务端ip,端口号)
服务端与客户端的socket其实可以理解为是一个,但不严谨
通过下图进行理解:
- 服务端的输出流由客户端的输入流接收;客户端的输出流由服务端的输入流接收。
- 一个管道代表一个线程,想实现双端通信至少需要两个线程
消息协议
消息具体如何发送?消息协议
TCP(传输控制协议):面向连接,能确认送达
UDP(用户数据报):给个地址,不管是否能送达,不需要建立连接
TCP
- 稳定性, 要求发送数据前必须确认双方都可以收发信息
- 连接过程:三次握手
过程1时客户端不知道服务端是否接受到
过程3时客户端收到回应消息确定服务端可以收到消息且可以发送消息
过程2时服务端知道客户端能够发送消息但不知道客户端是否能够接受消息
过程4时服务端知道客户端能够接受消息 此时建立稳定连接
- 以上过程通过syn(同步包)ack(响应包) fin(结束包)来实现
收发信息模拟
服务端向客户端发送字符串:字符串—>字节,一个个发送出去
客户端从服务端收到字符串:字节—>字符—>字符串
文字消息:
- 先读取消息的长度,定义一个固定容量的大小容器
- 对方收到对应长度字节,转为String对象
还需要退出 中断连接释放资源
发送字符串长度
String msg=new String("服务器连接成功!!!");
byte [] msgbyte=msg.getBytes();
outputStream.wait(msgbyte.length);
发送消息主体
outputStream.write(msgbyte);
outputStream.flush();
注意:byte是0-127所以最多只能发送127个字节
收到字符串长度
int msglength=inputStream.read(); //读取字符串长度
System.out.println("消息长度是"+msglength);
byte[] msgbyte=new byte[msglength];//服务器连接成功!!!10个字符20个字节
收到字符串
inputStream.read(msgbyte);//服务端将数据发送到客户端,客户端通过输入流从客户端读取数据放在数组里
String getmsg=new String(msgbyte); //将msgbyte转成字符串
System.out.println("服务器发送过来说:"+getmsg);
代码
MsgClient
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class MsgClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket=new Socket("127.0.0.1",8888);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
int msglength=inputStream.read(); //读取字符串长度
System.out.println("消息长度是"+msglength);
byte[] msgbyte=new byte[msglength];//服务器连接成功!!!10个字符20个字节
inputStream.read(msgbyte);//服务端将数据发送到客户端,客户端通过输入流从客户端读取数据放在数组里
String getmsg=new String(msgbyte); //将msgbyte转成字符串
System.out.println("服务器发送过来说:"+getmsg);
}
}
MsgServer
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MsgServer {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serversocket=new ServerSocket (8888);
//通过ServerSocket建立连接然后获得连接后的socket对象
System.out.println(serversocket.getInetAddress().getHostAddress()+"等待连接。。。。。。。。。。。。。");
Socket clientsocket=serversocket.accept();
System.out.println(serversocket.getInetAddress()+"连接成功"+clientsocket.getInetAddress()+clientsocket.getPort());
InputStream inputStream = clientsocket.getInputStream();
OutputStream outputStream = clientsocket.getOutputStream();
String msg=new String("服务器连接成功!!!");
byte [] msgbyte=msg.getBytes();
outputStream.write(msgbyte.length);
outputStream.write(msgbyte);
outputStream.flush();
while(inputStream.read()!=-1) //-1代表没有数据
{
System.out.print((char)inputStream.read());
}
}
}