Socket:英文中的意思是插座。
两个Java应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为一个Socket。
Java中所有关于网络编程的类都位于java.net包。
一、TCP的socket编程
TCP编程需要使用的两个类:Socket类与ServerSocket类,
分别用来实现双向连接的Client端和Server端。
说明:这里仅指TCP连接。因为UDP中没有Client和Server的概念。UDP只负责发送,不管是否发生成功。
建立连接时所需要的寻址信息为远程计算机的IP地址和端口号。
说明:
1.一个端口号只能被一个应用程序占用。
2.1024以下的端口号都由系统使用。普通应用程序不应该去占用。
3.比较有名的应用程序占用某个特定的端口号,一般也不该去占用。
如HTTP端口,80端口。
FTP,21端口。
SMTP,25端口。
接受邮件,110端口。
说明:TCP端口与UDP端口是两个不同的概念。TCP端口有65535个端口,UDP端口也有65536个端口。TCP的8888端口与UDP的8888端口是两个不同的概念。
ServerSocket的构造函数
ServerSocket() ServerSocket(int port) |
创建非绑定服务器套接字。 创建绑定到特定端口的服务器套接字。 |
ServerSocket常用API
Socket accept() 侦听并接受到此套接字的连接。该方法为阻塞方法,当没有接收到新的网络连接前是不会继续执行的。
Socket的构造函数
Socket() Socket(String host, int port) |
若没建立连接会抛出异常。 |
例程
例:TCP的Server端
import java.net.*; import java.io.*; public class TCPServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); //建立监听 while(true) { Socket s = ss.accept();//等待请求。若请求,则创建Socket,即建立连接。 System.out.println("a client connect!"); //输入流 DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF());//从流中读出信息。 dis.close();//关闭流。 s.close();//关闭socket。 } } }
例:TCP的Client端
import java.net.*; import java.io.*; public class TCPClient { public static void main(String[] args) throws Exception { Socket s = new Socket("127.0.0.1", 6666); //建立Socket,寻址,申请连接。 OutputStream os = s.getOutputStream(); //使用流做通信。输出流 DataOutputStream dos = new DataOutputStream(os); Thread.sleep(30000); dos.writeUTF("hello server!");//以UTF-8的编码将数据写入流。 dos.flush(); //压出流中所有信息。 dos.close(); //关闭流。 s.close(); //关闭socket。 } }
说明:
1. 网络应用程序的编程过程中,应该先启动Server再启动Client。而编程过程是Server与Client是同时编写的。
2. ServerSocket类的accept()方法是阻塞式的方法,即若没有接受到连接,则停止在该方法,不再继续执行。
3. 在例程中readUTF()方法也是阻塞式的方法。
4. Client端的端口是系统自动选择的,我们不需要去关注。
例程的缺点
1. 由于Server端的readUTF()方法是阻塞式的。Server需要等待Client发送数据才会继续执行,所以将会导致accept()方法无法执行。
2. 由于readUTF方法是阻塞方式的。所以如果read()和write()方法是在同一个处理过程中,必须是一段是先读后写,另一端是先写后读。若两个都是先后后写,则Server端和Client都不会继续执行。
InetAddress:IP地址的超集。除了IP地址。还可以表示其他通信协议的地址。
二、UDP编程
UDP是不可靠的。UDP是基于数据报的形式发送数据。(TCP也本质也以数据报发送,但安全性强。)
对与UDP没有Server与Client的概念。
UDP编程中最重要的两个类:DatagramPacket与DatagramSocket
DatagramPacket类:
DatagramSocket类:
例程:
例:UDP的Server端
import java.net.*; import java.io.*; public class TestUDPServer { public static void main(String args[]) throws Exception { byte buf[] = new byte[1024]; //创建数据报。 DatagramPacket dp = new DatagramPacket(buf, buf.length); //该数据报与字节数组关联。 DatagramSocket ds = new DatagramSocket(5678); //占用5678端口。 while(true) { ds.receive(dp);//接受数据报。并把数据报传递至dp。即数据报中的数据存入buf。 ByteArrayInputStream bais = new ByteArrayInputStream(buf); //从字节数组(源)接上读取流。 DataInputStream dis = new DataInputStream(bais); //用Data流包装读取流。 System.out.println(dis.readLong()); //从Data流中读取数据。 } } }
例:TCP的Client端
import java.net.*; import java.io.*; public class TestUDPClient { public static void main(String args[]) throws Exception { //首先将一个long数,装为字节数组。 long n = 10000L; ByteArrayOutputStream baos = new ByteArrayOutputStream(); //创建写入内存的流(字节数组流)。该流用于向内存写数据。 DataOutputStream dos = new DataOutputStream(baos); //用数据流包装内存流。 dos.writeLong(n); //向数据流中写入long数。数据流负责把任何类型的数据写到内存流。通过内存流数据写到内存中。 byte[] buf = baos.toByteArray(); //从内存流(字节数组流)中得到long数的byte数组。 //创建数据报。 DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 5678) ); DatagramSocket ds = new DatagramSocket(9999); //占用9999端口。 ds.send(dp); //发送数据报。 ds.close(); //关闭通信socket。 } }
说明:
DatagramSocket类的receive()方法阻塞式的方法。
InetAddress类继承了SocketAddress类。