通信从零起步
服务器与客户端
1. Socket与socket
大写的Socket表示库,小写的socket表示程序组件的名称。
套接字可以理解为管道两端的接口,在通信过程中它记录用于控制通信操作的各种控制信息。在协议栈内部有一块用于存放控制信息的内存空间,这里记录了用于控制通信 操作的控制信息,像IP地址,端口号,通信操作的进行状态等等,在某种意义上可以将其看作为套接字的实体。
我们创建套接字时,就会增加类似上图的一行新的控制信息,赋予“即将开始通信的状态”,并进行通信的准备工作,如分配用于临时存放和收发数据的缓冲区空间。
代码表达:
Socket socket = new Socket(“127.0.0.1”,9090);//进行内存空间的分配,并在其中写入控制信息。(InetAddress addr, int port)我们上面代码的两个参数是IP地址和端口。
客户端创建套接字之后会用管道连接服务器端的套接字,处于连接阶段。
服务器创建套接字,会将套接字设置为等待连接状态。
(这里我猜测后面服务器用的方法不一样可能就是这个问题吧)
2. ServerSocket
Socket是我们创建在客户端的套接字,对于服务器这一端也要和客户端建立通信。一般一个服务器对应于多个客户端。ServerSocket等待客户端的请求,当获得连接请求的时候,就创建一个Socket实例来与客户端进行通信。
ServerSocket socket = new ServerSocket(port);//创建服务器套接字,并将其绑定到指定的本地端口。
- socket.accept()
连接操作,服务器一直处于等待连接的状态,当连接到达的时候,创建一个Socket实例。accept结束后启动客户端通信模块,然后将连接好的套接字转交给客户端通信模块,由这个模块来负责执行和客户端之间的通信操作。
Socket ser = serSocket.accept();//该方法的返回值为Socket的实例对象
3. 代码演示——尝试连接
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",9090);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Server {
public static void main(String[] args) {
try {
ServerSocket serSocket = new ServerSocket(9090);
serSocket.accept();
System.out.println("客户端连接成功");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OutputStream与InputStream
当进行通信的时候,是以二进制的形式进行数据的传输,文字,图片,视频等等都需要将其转为二进制,作为被传输的对象。所以在通信过程,我们需要借助于 OutputStream(输出流)与InputStream(输入流)来实现数据的发送与接收。
1. OutputStream
这是帮助文档中展现的内容,它的功能是接受输出字节并将这些字节发送到某个接受器。
我们看一下它的方法:
我们现在就可以利用out.write(byte[] b)来发送数据。
out.flush(); 当我们发送数据到最后的时候,要加上清空管道的工作,确保数据全部发送
2. InputStream
输入流就相应的作为数据接收方,来读取字节。
fang
我们可以利用input.read()方法读取需要的内容。
3. 从客户端(服务器)获取输入输出流
当我们输出读取数据的时候,要有相应的对象,是谁在发送数据,谁在读取数据。我们下面的四行代码虽然同样的out(input)但其中的含义是不一样的,因为指代的对象不同。
out = socket.getOutputStream();//从客户端的套接字获取输出流
input = socket.getInputStream();//从客户端的套接字获取输入流
out = ser.getOutputStream();//从服务器的套接字获取输出流
input =ser.getInputStream();//从服务器的套接字获取输出流
对于我们的写操作是主动的,读却是被动的。一旦有数据过来,就需要将这些数据读入,所以我们设置了死循环,使客户端和服务器都一直处于读的状态,有数据发送并发送结束后,就可以立即响应。
4. 代码演示——数据传输
客户端:
package com.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
try {
String read = "";
Socket socket = new Socket("127.0.0.1",9090);
OutputStream out = socket.getOutputStream();
InputStream input = socket.getInputStream();
out.write("I am client!\r".getBytes());
out.flush();
while(true){
byte c = (byte) input.read();
if(c != 13){
read += (char)c;
}else {
System.out.println("read = "+read);
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
成功接收来自服务器的数据!
服务器:
package com.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
try {
String read = "";
ServerSocket serSocket = new ServerSocket(9090);
Socket ser = serSocket.accept();
OutputStream out = ser.getOutputStream();
InputStream input = ser.getInputStream();
out.write("I am Server!\r".getBytes());
out.flush();
while(true){
byte c = (byte) input.read();
if(c != 13){
read += (char)c;
}else {
System.out.println("read = "+read);
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
成功接受来自客户端的数据
附:这里把字符串转为了字节一个个发送
发送图形坐标数据,文字,图片
字节数组和int型的相互转换.
流中写入文字和图片.
实现图片发送后,对于视频就迎刃而解。视频是由多张图片在短时间内不断播放形成的,所以我们发送视频相当于连续发送图片。
主界面
学到通信的小伙伴,对于界面的建立应该是很轻松的。我认为在这里可以先思考如何布局,由于整个界面的组件是很琐碎的,所以要想有一个自己内心所想的界面真的需要建立草稿图,梳理好组件添加的逻辑顺序。
这张图片是我现在的界面布局,其实也并不是十分理想!!!
我把布局还要继续搞明白。
当连接成功之后,让双方同时启动面板即可。
我们进行的通信,想达成同步的操作,同样的UI应该是没有问题的,效果展示的也会展示的更加充分。
界面显示:
这个是我目前达到的效果。
实现画图和文字传输,发送后发送框中的文字清空
界面有如此丰富效果的原因
- ActionListener响应按钮事件
- MouseListener,MouseMotionListener的响应事件
对不同事件传输原理
就像我们每个人都有自己的身份证号可以证明自己独一无二的身份。当我们进行数据发送的时候也要给出相应的标识符。例如,当进行画图同步时,可以先写入标识符数字1;当我们发送文字的时候,可写入标识符数字2;后面的就不详细叙述了。
源代码就给大大家放在链接中提供下载。
目前遇到的问题和待解决方案
- 当进行视频通话的时候,传输文字的按钮失效
解决方案:利用多线程看能不能解决问题