Socket编程相关类
(1)Socket类 Socket类的对象表示一个套接字。客户端使用Socket类的构造方法创建套接字,创建的同时会自动向服务器方发起连接。 Socket类有如下一些构造方法。
Socket(String host, int port) throws UnknownHostException, IOException:向服务器(域名host,端口号port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
Socket(InetAddress address, int port) throws IOException:同上。只是根据InetAddress对象所表示的IP地址以及端口号port发起连接。
Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException:创建一个套接字并将其连接到指定远程主机上的指定端口。Socket会通过调用bind()方法来绑定提供的本地地址及端口。host表示远程主机名,port表示远程端口号,localAddr表示要将套接字绑定到的本地地址,localPort表示要将套接字绑定到的本地端口。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException:创建一个套接字并将其连接到指定远程地址上的指定端口。Socket会通过调用bind()方法来绑定提供的本地地址及端口。
Socket类的常用方法
方 法 | 功 能 |
InetAddress getLocalAddress() | 返回对方Socket中的IP的InetAddress对象 |
int getLocalPort() | 返回本地Socket中的端口号 |
InetAddress getInetAddress() | 返回对方Socket中IP地址 |
int getPort() | 返回对方Socket中的端口号 |
void close() throws IOException | 关闭Socket,释放资源 |
InputStream getInputStream()throws IOException | 获取与Socket相关联的字节输入流,用于从Socket中读数据 |
OutputStream getOutputStream()throws IOException | 获取与Socket相关联的字节输出流,用于向Socket中写数据 |
(2)ServerSocket类
服务器端需要一个监听特定端口的套接字,使用ServerSocket类创建。ServerSocket等待客户端发起连接,然后返回一个用于与该客户进行通信的Socket对象。 ServerSocket类有如下一些构造方法。
ServerSocket(int port) throws IOException:创建绑定到特定端口的监听套接字。连接队列的最大长度是50,当队列已满又有客户端发起连接请求时,服务器将拒绝该请求。连接队列是指已完成TCP三次握手但还没被accept()取走的连接。
ServerSocket(int port, int backlog) throws IOException:利用指定的backlog创建监听套接字并将其绑定到指定的本地端口号。backlog表示队列的最大长度。
ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException:使用指定的端口、队列长度和要绑定到的本地IP地址创建监听套接字,bindAddr表示要将套接字绑定到的地址。
ServerSocket类的常用方法
方 法 | 功 能 |
Socket accept() throws IOException | 等待客户端的连接请求,返回与该客户端进行通信用的Socket对象 |
void setSoTimeout(int timeout) throws SocketException | 设置accept()方法等待连接的时间为timeout毫秒。若时间已到还没有客户端连接,则抛出InterruptedIOException异常,accept()方法不再阻塞,该监听Socket可继续使用。若timeout为0表示永远等待。该方法必须在监听Socket创建后、accept()之前调用才有效 |
void close()throws IOException | 关闭监听Socket |
InetAddress getInetAddress() | 返回此服务器套接字的本地地址 |
int getLocalPort() | 返回此套接字在其上监听的端口号 |
SocketAddress getLocalSocketAddress() | 返回此套接字绑定的端点的地址 |
(3)InetAddress类
InetAddress类的对象表示IP地址,该类没有构造方法
方 法 | 功 能 |
static InetAddress[] getAllByName(String host) throws UnknownHostException | 返回主机名host所对应的所有IP,每一个IP用一个InetAddress对象表示,结果返回的是一个一维的InetAddress数组 |
static InetAddress getByName(String host) throws UnknownHostException | 返回主机名host所对应的一个IP。若该主机名对应多个IP,则随机返回其中一个。该IP用InetAddress对象表示 |
static InetAddress getLocalHost()throws UnknownHostException | 返回本地主机的IP地址。该IP用InetAddress对象表示 |
public byte[] getAddress() | 返回组成该IP地址的4个字节。按网络字节存放,即最高字节放在getAddress()[0]中 |
static InetAddress getByAddress(byte[] addr) throws UnknownHostException | 返回由该4个字节组成的IP地址的InetAddress对象 |
Byte[] getAddress() | 返回IP地址的4个字节组成的数组 |
例题:返回域名相应的IP地址,若没有给出域名,则返回本地主机的IP地址。
运行程序,在文本框中输入新浪的域名“www.sina.com”回车,则在列表框中显示新浪及本机的IP地址信息
程序的运行结果:
源代码部分:
InetAddressTest.java
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class InetAddressTest {
static TextField tf1 = new TextField(40);
static List list = new List(6);
public static void main(String[] args) throws Exception {
Frame f = new Frame();
f.add(list);
f.setSize(300, 100); // 设置窗体的大小
Panel p = new Panel();
p.setLayout(new BorderLayout()); // 设置边界布局管理器
tf1.addActionListener(new MyListener()); // 注册事件监听器
p.add("West", tf1);
f.add("South", p);
f.addWindowListener(new WindowAdapter() { // 关闭窗口
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setVisible(true);
}
}
class MyListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String s = InetAddressTest.tf1.getText(); // 获取文本框中的内容
InetAddress[] addr;
InetAddress addr2;
try {
InetAddressTest.list.removeAll(); // 将列表框中的原有内容清除
addr = InetAddress.getAllByName(s); // 返回主机名所对应的所有IP地址
addr2 = InetAddress.getLocalHost(); //返回本机的ip地址
for (int i = 0; i < addr.length; i++) {
InetAddressTest.list.add(addr[i].toString()); // 添加到列表框中
}
InetAddressTest.list.add(addr2.toString()); // 将本地主机的IP地址添加到列表框里
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
((TextField) e.getSource()).setText(null); // 设置文本框的内容为空
}
}
【例14.2】一个简单TCP通信程序,客户端向服务器发送任意字符串,服务器收到后显示。
运行上面两个程序,首先在客户端文本框中输入一些字符,按回车键,这些字符显示在客户端窗口中。并且,这些数据还发送给了服务器端,服务器接收到从客户端发来的字符也显示在窗口上
服务器端:
客户端:
程序运行结果:
源代码部分:
服务器端:TCPServer.java
package org;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class TCPServer {
static DataInputStream dis = null;
public static void main(String[] args) {
boolean started = false;
Socket s = null;
TextArea ta = new TextArea();
ta.append("从客户端接受的数据:"+"\n");
ServerSocket ss = null;
try {
ss = new ServerSocket(8866); // 创建一个监听Socket对象
} catch (BindException e) {
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
Frame f = new Frame("服务器端");
f.setLocation(300, 300);
f.setSize(200, 200);
f.add(ta, BorderLayout.NORTH);
f.pack();
f.addWindowListener(new WindowAdapter() { // 关闭窗口
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setVisible(true); // 设置窗体可见
try {
started = true;
while (started) {
boolean bConnected = false;
s = ss.accept(); // 等待客户端请求连接
bConnected = true;
dis = new DataInputStream(s.getInputStream());
while (bConnected) {
String str = dis.readUTF(); // 从输入流中读取数据
str.length();
ta.append(str+",字符串长度:"+str.length()+"\n"); // 将数据添加到文本区中
}
}
} catch (EOFException e) {
System.out.println("Client closed!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null)
dis.close(); // 关闭 输入流
if (s != null)
s.close(); // 关闭Socket对象
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
客户端TCPClient.java
package org;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class TCPClient extends Frame {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
TextField tf = new TextField(40);
List list = new List(6);
public static void main(String[] args) {
TCPClient client = new TCPClient();
client.list.add("向服务器端发送的数据:");
client.setTitle("客户端");
client.run();
}
public void run() {
setLocation(400, 300); // 设置窗体的位置
this.setSize(300, 300); // 设置窗体的大小
add(tf, BorderLayout.SOUTH);
add(list, BorderLayout.NORTH);
pack();
this.addWindowListener(new WindowAdapter() { // 关闭窗体
public void windowClosing(WindowEvent e) {
disconnect();
System.exit(0);
}
});
tf.addActionListener(new MyListener()); // 注册 事件监听器
setVisible(true);
connect();
}
public void connect() {
try {
s = new Socket("127.0.0.1", 8866); // 创建一个向服务器发起连接的Socket对象
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
dos.close(); // 关闭输出流
s.close(); // 关闭Socket对象
} catch (IOException e) {
e.printStackTrace();
}
}
private class MyListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String s1 = null;
String s2 = null;
String str = tf.getText().trim(); // 获取文本框中的内容
list.add(str);
tf.setText(""); // 将文本框的内容清空
try {
dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(str); // 向流中写入数据
dos.flush(); // 刷空流
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}