Java Socket通信
今天讲解的是JAVA中通常用的一种通信方法,通过一个双向的通信连接实现数据的交换,其中一端称为Socket。
基本原理为:
Socket socket=new Socket( 服务器,端 口)
输出流.write( 数据) 和 byte b=输入流 .read ()
在传送过程中,数据像包裹意向被层层通信协议封装起来,最常见的就是TCP/IP 通信协议,在网络上传输时,首先包装为TCP格式,再包装为IP格式 。
因为Socket实现的是UDP传送,UDP 通信不用建立连结就可发送,只负责发送,不保证接收的有效性,所以在进行大量数据流传送时可能会出现丢包现象。
通信分为客户端和服务端,可利用如下代码实现简单的 UDP 客户机和服务间通信
发送端
//UDP发送端:一台机器可能有多个IP地址,
//把数据以本机192.168.1.147地址上13000号端号,发送到192.168.1.149上的14000端口
//1.创建要用来发送的本地地址
SocketAddress localAddr = new InetSocketAddress("192.168.1.147", 13000);
//2.创建发送的Socket对象
DatagramSocket dSender = new DatagramSocket(localAddr);
int count=0;
while(true){
count++;
byte buffer[] = (count+"-hello").getBytes();//3.要发送的数据
//4.发送数据的目标地址和端口
SocketAddress destAdd = new InetSocketAddress("192.168.1.149", 14000);
//5.创建要发送的数据包,指定内容,指定目标地址
DatagramPacket dp = new DatagramPacket(buffer, buffer.length, destAdd);
dSender.send(dp);//6.发送
System.out.println("数据已发送: "+count);
Thread.sleep(1000);
}//end while
接收端
//1.接收端:在本机接收的机址和等待的端口号
SocketAddress localAddr = new InetSocketAddress("192.168.1.149", 14000);
//2.接收的服务器UDP端口
DatagramSocket recvSocket = new DatagramSocket(localAddr);
while(true){
byte[] buffer = new byte[20]; //3.指定接收缓冲区大小:每个包20字节
//4.创建接收数据包对象
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//5.阻塞等待数据到来,如果收到数据,存入packet中的缓冲区中
System.out.println("UDP服务器等待接收数据:");
recvSocket.receive(packet); //6.在此等待接收对方发的UDP包
//得到发送方的IP和端口
SocketAddress address = packet.getSocketAddress();
//转换接收到的数据为字符串
String msg=new String(packet.getData()).trim();
//接收到后,打印出收到的数据长度
System.out.println("recv is:"+msg+" from:"+address);
}
在此我设置了一个聊天页面,同时承担发送和接收任务,放入程序中运行的完整代码为
//主函数
public class Client1Message {
public static void main(String[] args){
Client1Message me = new Client1Message();
me.initUI();
}
public void initUI(){
JFrame jf = new JFrame();
jf.setSize(300,350);
jf.setTitle("Message-Client1");
jf.setDefaultCloseOperation(3);
java.awt.FlowLayout flow = new java.awt.FlowLayout();
jf.setLayout(flow);
JTextField jtf = new JTextField(20);//单行文本框
jf.add(jtf);
JButton jb = new JButton("Send");
jf.add(jb);
JTextArea jta = new JTextArea();//多行文本框
jta.setPreferredSize(new Dimension(290,300));
jf.add(jta);
jf.setVisible(true);
Pass1 pass = new Pass1(jtf);
Receive1 rec = new Receive1(jta);
jb.addActionListener(pass);
rec.start();
}
}
//发送命令封装的类
public class Pass1 implements ActionListener{
public JTextField jtf;
public int localpost=13000;
public int recpost=14000;
public SocketAddress localAddr = new InetSocketAddress("192.168.31.28", localpost);
public DatagramSocket dSender;
public void actionPerformed(ActionEvent e) {
// System.out.println(pass);
send();
}
public Pass1(JTextField jtf){
this.jtf = jtf;
try {
dSender = new DatagramSocket(localAddr);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void send(){
try {
byte buffer[]= jtf.getText().getBytes() ;//3.要发送的数据
//4.发送数据的目标地址和端口
SocketAddress destAdd = new InetSocketAddress("192.168.31.28", recpost);
//5.创建要发送的数据包,指定内容,指定目标地址
DatagramPacket dp = new DatagramPacket(buffer, buffer.length, destAdd);
dSender.send(dp);//6.发送
System.out.println("Client1已发送: "+jtf.getText());
} catch (SocketException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//接收命令封装的类
public class Receive1 extends Thread{
public JTextArea jta;
public SocketAddress localAddr= new InetSocketAddress("192.168.31.28", 12000);
public SocketAddress destAdd;
public DatagramSocket recvSocket;
public Receive1(JTextArea jta){
this.jta = jta;
}
public void run(){
//2.创建发送的Socket对象
try {
recvSocket = new DatagramSocket(localAddr);
// while (true) {
byte[] buffer1 = new byte[20]; // 3.指定接收缓冲区大小:每个包20字节
// 4.创建接收数据包对象
DatagramPacket packet1 = new DatagramPacket(buffer1, buffer1.length);
System.out.println("Client1等待接收数据:");
while (true) {
//5.阻塞,等待数据到来,如果收到数据,存入packet中的缓冲区中
recvSocket.receive(packet1); // 6.在此等待接收对方发的UDP包
//得到发送方的IP和端口
destAdd = packet1.getSocketAddress();
System.out.println("Client1得到发送方的端口和IP:"+destAdd);
// 转换接收到的数据为字符串
String msg = new String(packet1.getData());
// 接收到后,打印出收到的数据长度
jta.append(msg + "\n");// 显示在文本框里
System.out.println("recv is:" + msg + " from:" +"Client2");
}
} catch (SocketException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注意:在进行测试时,两台电脑应在同一wifi下进行连接测试,或是一台电脑在wifi下利用不同的收发端口自测。
界面显示结果为