通信阶段总结
学习通信有两点是我们需要学习的,一个是客户端与服务器的连接,一个是协议的制定。
对于客户端与服务器的连接,其实掌握几行代码就能轻松解决:
首先我们先建立一个客户端:
Socket client = new Socket(IP,port);
这样就建立了一个客户端,在这里只要传入一个连接时需要使用的IP地址和端口号就OK了。建立服务器并且实现与客户端的连接。
ServerSocket server = new ServerSocket(port);
在指定的端口创建服务器,然后就可以等待客户端的连接。
Socket client = server.accept();
通信主要是进行信息的发送,接收和发送信息主要是通过流来实现的,最重要的是,我们发送信息使用的流一定要和接收信息使用的流一致,这样才能保证数据的传送正确。
一:文本的发送:信息发送一般发送的是字节,当然也可以发送int数值或者是一个缓冲的字节数组。
代码如下:
//client作为一个管道进行输入输出流的通道
in = client.getInputStream();
dis = new DataInputStream(in);
out = client.getOutputStream();
有了管道我们就可以发送消息了,消息不论是从客户端向服务器发送还是从服务器向客户端发送,所用的方法一样
//向服务器发送消息
out.write(("Client:"+str+"\r\n").getBytes());
ClientUI.ja1.append(str+"\r\n");
out.flush();
System.out.println("客户端已发送信息");
因为发送是以字节发送的,所以接收的时候我们也要使用相同的方法
int i=in.read();
StringBuffer sb = new StringBuffer();
//回车键的时候终止循环
while(i!=13){
sb.append((char)i);
i = in.read();
}
fromServer = sb.toString().trim();
System.out.println("fromServer="+fromServer);
//显示在构造的面板上
ClientUI.ja1.append(fromServer+"\r\n");
二:以画板的形式传送图片
所谓传送图片我们传送的仍然是字节或者int型的数值,下面是以传送直线为例的,两点确定一条直线,所以我们只要传送四个数值就可以了。
//发送坐标的方法
public static void sendPoint() {
try{
// 利用DataOutputStram没有OutputStream只发送0-255之间的限制
DataOutputStream dos = new DataOutputStream(out);
out.write(2);
//获取监听器中获得的坐标,然后发送出去
dos.writeInt(ClientDrawListener.x1);
dos.writeInt(ClientDrawListener.y1);
dos.writeInt(ClientDrawListener.x2);
dos.writeInt(ClientDrawListener.y2);
}catch(Exception e){
e.printStackTrace();
}
}
//利用与DataOutputStream对应的DisInputStream流
int x1 = dis.readInt(); //获取读到的x1坐标
int y1 = dis.readInt(); //获取读到的y1坐标
int x2 = dis.readInt();
int y2 = dis.readInt();
System.out.println("client接收到:");
System.out.println("=========="+x1+" "+y1+" "+x2 +" "+y2);
//获取到坐标以后便在面板上画出相应的图形
ClientUI.gc.drawLine(x1, y1, x2, y2);
三:传送文件
传送文件其实和传送文本一致,首先我们要在发送文件的按钮上添加监听器。
JButton jb3 = new JButton("发送文件");
//给发送文件按钮添加监听器
jb3.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
JFileChooser jf = new JFileChooser();
//在ClientUI上显示文件选择器
jf.showOpenDialog(ClientUI.this);
//文件选择模式
jf.setFileSelectionMode (JFileChooser.FILES_AND_DIRECTORIES);
//获得选择的文件
chFile = jf.getSelectedFile();
//获得选择的文件的路径
frompath = chFile.getAbsolutePath();
//获得文件名
fileName = chFile.getName();
try {
Client.sendFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
this.add(jb3);
在文件选择器中选取文件后,我们已经获取了文件名和文件大小,下面我们直接就可以进行发送了
/**
* 发送文件
* @throws IOException
*/
public static void sendFile() throws IOException{
//输出流
DataOutputStream dos = new DataOutputStream(out);
//首先要写出发送的类型
out.write(3);
//写出文件大小
dos.writeInt((int) ClientUI.chFile.length());
//要写出文件名
dos.writeUTF(ClientUI.fileName);
//创建一个专门读取文件的流
FileInputStream fis = new FileInputStream(ClientUI.chFile);
//封装在data流中f
DataInputStream disf = new DataInputStream(fis);
//获取文件的大小以便于写出文件
for(int i=0;i<ClientUI.chFile.length();i++){
//从文件中读取字节
byte fromfile = disf.readByte();
System.out.println("从文件中获取的字节:"+fromfile+" "+(char)fromfile);
//然后写出文件到管道中去
dos.writeByte(fromfile);
}
}
最后,我们把文件用相同的流去接收就OK啦。
//管道输入流
DataInputStream dis = new DataInputStream(in);
String path = "D:\\aa.txt";
//输入到新的文件的输入流
File tof = new File(path);
FileOutputStream fos = new FileOutputStream(tof);
DataOutputStream dosf = new DataOutputStream(fos);
//接收文件的大小
int flength = dis.readInt();
System.out.println("文件大小为:"+flength);
//要接收文件名
String fileName = dis.readUTF();
System.out.println("文件名为:"+fileName);
//将接收到的文件名写入到新的文件中去
dosf.writeUTF(fileName);
StringBuffer sb = new StringBuffer();
//接收文件内容,要接收字节
String str = null;
for(int i = 0;i<flength;i++){
byte bf = dis.readByte();
System.out.println("收到的字节:"+(char)bf);
str = sb.append((char)bf).toString().trim();
System.out.println("转化为字符串为:"+str);
dosf.writeChar((char)bf);
}