开发工具与关键技术:MyEclipse 10、TCP
作者:邓崇富
撰写时间:2019 年 5 月 7 日
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TCP网络程序设计是利用Socket类编写通信程序。利用TCP协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序。
InetAddress类
Java.net包中的InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
InetAddress类的常用方法如下表:
方 法 | 返 回 值 | 说 明 |
getByName(String host) | InetAddress | 获取与Host相对应的InetAddress对象 |
getHostAddress() | String | 获取InetAddress对象所包含的IP地址 |
getHostName() | String | 获取IP地址的主机名 |
getLocalHost | InetAddress | 返回本地主机的InetAddress对象 |
使用InetAddress类的getHostName()和getHostAddress()方法获得本地主机名、本机IP地址。
代码如下:
public class Address {
public static void main(String[] args) {
InetAddress ip;//创建InetAddress对象
try {
ip = InetAddress.getLocalHost();//实例化对象
String localname = ip.getHostName();//获取本机名
String localip = ip.getHostAddress();//获取本机IP地址
System.out.println("本机名:" + localname);
System.out.println("本机IP地址:" + localip);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
ServerSocket类
Java.net包中的ServerSocket类用于表示服务器套接字,其主要功能是等待来自网络上的“请求”,它可通过指定的端口来等待连接的套接字。服务器套接字一次可以与一个套接字连接。如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入列队中,然后从中取出一个套接字与服务器新建的套接字连接起来。若请求数大于最大容纳数,则多出的连接请求被拒绝。队列的默认大小是50。
ServerSocket类的构造方法都抛出IOException异常,分别有以下几种形式:
- ServerSocket():创建非绑定服务器套接字。
- ServerSocket(int port):创建绑定到特定端口的服务器套接字。
- ServerSocket(int port,int backlog):利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号。
- ServerSocket(int port,int backlog,InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP地址的情况,用于可以明确规定ServerSocket在哪块网卡或IP地址上等待客户的连接请求。
ServerSocket类的常用方法如下:
方 法 | 返 回 值 | 说 明 |
Accept() | Socket | 等待客户机的连接。若连接,则创建一套接字 |
isBound() | boolean | 判断ServerSocket的绑定状态 |
getInetAddress() | InetAddress | 返回此服务器套接字的本地地址 |
isClosed() | boolean | 返回服务器套接字的关闭状态 |
Close() | void | 关闭服务器套接字 |
Bind(SocketAddress endpoint) | void | 将ServerSocket绑定到特定地址(IP地址和端口号) |
getInetAddress() | int | 返回服务器套接字等待的端口号 |
调用ServerSocket类的accept()方法会返回一个和客户端Socket对象相连接的Socket对象,服务器端的Socket对象使用getOutputStream()方法获得的输出流将指向客户端Socket对象使用getInputStream()方法获得的那个输入流;同样服务器端的Socket对象使用getInputStream()方法获得的输入流将指向客户端Socket对象使用getOutputStream()方法获得的那个输出流。也就是说,当服务器向输出流写入信息时,客户端通过相应的输入流就能读取,反之亦然。
TCP网络程序
在网络编程中如果只要求客户端向服务器发送消息,不要求服务器向客户端发送消息,称为单向通信。客户端套接字和服务器套接字连接成功后,客户端通过输出流发送数据,服务器则通过输入流接收数据。
以下是简单的单向的通信的例子(服务端代码):
public class MyTcp {
private BufferedReader reader;// 创建BufferedReader对象
private ServerSocket server;// 创建ServerSocket对象
private Socket socket;// 创建Socket对象socket
void getsever() {
try {
server = new ServerSocket(8998);// 实例化Socket对象
System.out.println("服务器套接字已经创建成功");
while (true) {// 如果套接字是连接状态
System.out.println("等待客户级的连接");
socket = server.accept();// 实例化Socket对象
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 实例化BufferedReader对象
getClientMessage();// 调用getClientMessage()方法
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void getClientMessage() {
try {
while (true) {// 如果套接字是连接状态
// 获得客户端信息
System.out.println("客户机:" + reader.readLine());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if (reader != null) {
reader.close();// 关闭流
}
if (socket != null) {
socket.close();// 关闭套接字
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void main(String[] args) {
MyTcp tcp = new MyTcp();// 创建本类对象
tcp.getsever();// 调用方法
}
}
服务器运行结果:
先运行服务端程序,等输出提示信息,等待客户连接;再运行客户端程序。
以下是客户端程序代码:
public class MyClien extends JFrame {
private static final long serialVersionUID = 1L;
private PrintWriter writer;
Socket socket;
private JTextArea ta = new JTextArea();
private JTextField tf = new JTextField();
Container cc;
public MyClien(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cc = this.getContentPane();
final JScrollPane scrollPane = new JScrollPane();
scrollPane.setBorder(new BevelBorder(BevelBorder.RAISED));
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(ta);
cc.add(tf, "South");
tf.addActionListener(new ActionListener() {
// 绑定事件
@Override
public void actionPerformed(ActionEvent e) {
// 将文本框中的信息写入流
writer.println(tf.getText());
// 将文本框中的信息显示在文本域中
ta.append(tf.getText() + '\n');
ta.setSelectionEnd(ta.getText().length());
tf.setText("");
}
});
}
private void connect() {
ta.append("尝试连接\n");
try {
socket = new Socket("127.0.0.1", 8998);
writer = new PrintWriter(socket.getOutputStream(), true);
ta.append("完成连接\n");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MyClien clien = new MyClien("向服务器发送数据");
clien.setSize(300, 300);
clien.setVisible(true);
clien.connect();
}
}
客户端运行结果: