java linux api_JAVA Socket API与LINUX Socket API探究

本文探讨了JAVA的Socket API在实现网络通信时如何工作,通过实例展示了服务端和客户端的程序设计,并通过API调用栈追踪解析了JAVA如何调用底层系统接口。同时,与LINUX的Socket API进行了对比,说明了JAVA封装的便利性。
摘要由CSDN通过智能技术生成

代码

这是一个带有UI界面的JAVA网络聊天程序,使用Socket连接完成通信。

JAVA服务端程序

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.Scanner;

/**

* Server

*/

public class Server {

private static final int PORT = 4000; // 指定通信端口

public final String END_OF_MESSAGE = "$$";

public void launch() throws IOException {

ServerSocket server = new ServerSocket(PORT);

Socket requSocket = server.accept();

InputStream inStream = requSocket.getInputStream();

OutputStream outputStream = requSocket.getOutputStream();

Scanner in = new Scanner(inStream);

PrintWriter out = new PrintWriter(outputStream, true /* autoFlush */);

out.println("Welcome! Let's talk.");

while (in.hasNextLine()) {

String line = in.nextLine();

if (line.equals("Hello")) {

out.println("Hi");

} else if (line.equals("Bye")) {

out.println("Bye");

out.println(END_OF_MESSAGE);

break;

} else {

out.println("Can't understand what you said!");

}

}

in.close();

out.close();

server.close();

}

public static void main(String[] args) throws IOException {

new Server().launch();

}

}

客户端程序

import java.io.*;

import java.awt.event.*;

import java.net.*;

import java.text.SimpleDateFormat;

import java.util.*;

public class Client {

private static final String IP = "127.0.0.1"; // 使用本机地址

private static final int PORT = 4000;

private final String LINK_FAIL = "====================\n Connection build failed!\n";

private final String UNKOWN_HOST = "====================\n Unkown host!\n";

private final String IO_EXCEPTION = "====================\n I/O wrong!\n";

public static final String END_OF_MESSAGE = "$$";

private Socket userSocket;

private String userName;

private InputStream inStream;

private Scanner in;

private OutputStream outStream;

private PrintWriter out;

protected boolean serverStop;

public Client(String name) {

userName = name;

}

public void launch() {

UserInterface.creatUI(userName); // 创建一个用户界面

boolean error = false;

try {

creatConnection();

} catch (ConnectException e) {

UserInterface.chatWindow.append(LINK_FAIL);

error = true;

} catch (UnknownHostException e) {

UserInterface.chatWindow.append(UNKOWN_HOST);

error = true;

} catch (IOException e) {

UserInterface.chatWindow.append(IO_EXCEPTION);

error = true;

}

if (error) {

shutDown();

return;

}

String greeting;

while ((greeting = in.nextLine()) == null)

;

serverStop = false;

UserInterface.chatWindow

.append(new SimpleDateFormat("MM-dd HH:mm").format(new Date()) + "\n" + "Server: " + greeting + "\n\n");

UserInterface.sendButton.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

String message = UserInterface.inputText.getText();

if (serverStop || message.equals(""))

return;

out.println(message);

String currentTime = new SimpleDateFormat("MM-dd HH:mm").format(new Date());

UserInterface.chatWindow.append(currentTime + "\n" + userName + ": " + message + "\n\n");

UserInterface.inputText.setText("");

UserInterface.inputText.requestFocus();

String line = in.nextLine();

if (line.equals(END_OF_MESSAGE)) {

serverStop = true;

shutDown();

UserInterface.sendButton.setEnabled(false);

} else {

currentTime = new SimpleDateFormat("MM-dd HH:mm").format(new Date());

UserInterface.chatWindow.append(currentTime + "\n" + "Server: " + line + "\n\n");

}

}

});

}

private void creatConnection() throws ConnectException, NullPointerException, IOException {

try {

userSocket = new Socket(IP, PORT);

inStream = userSocket.getInputStream();

in = new Scanner(inStream);

outStream = userSocket.getOutputStream();

out = new PrintWriter(outStream, true /* autoFlush */);

} catch(ConnectException connectException) {

throw connectException;

} catch(NullPointerException nullPointerException) {

throw nullPointerException;

} catch(IOException ioException) {

throw ioException;

}

}

private void shutDown() {

in.close();

out.close();

try {

userSocket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

Client client = new Client("Tinshine");

client.launch();

}

}

用户界面

使用JAVA的swing组件实现一个简单的聊天窗口

import javax.swing.*;

import java.awt.*;

/**

* UserInteface

*/

public class UserInterface {

private final static String APP_NAME = "MSN";

public static String nameOfUser;

private static JFrame frame;

private static JPanel background;

private static JPanel sendPanel;

public static JTextArea chatWindow;

public static JTextField inputText;

public static JButton sendButton;

public static JScrollPane chatWinJScrollPane;

public static JScrollBar chatWinJScrollBar;

public static Point chatWinJScrollPoint;

public static void creatUI(String userName) {

nameOfUser = userName;

frame = new JFrame(APP_NAME);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

background = new JPanel();

background.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));

background.setLayout(new BoxLayout(background, BoxLayout.Y_AXIS));

chatWindow = new JTextArea(10, 10);

chatWindow.setLineWrap(true);

chatWinJScrollPane = new JScrollPane(chatWindow);

chatWinJScrollBar = chatWinJScrollPane.getVerticalScrollBar();

chatWinJScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

chatWinJScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

background.add(chatWinJScrollPane);

sendPanel = new JPanel();

sendPanel.add(new JLabel(userName + ": "));

inputText = new JTextField(20);

inputText.requestFocus();

sendPanel.add(inputText);

sendButton = new JButton("Send");

sendPanel.add(sendButton);

background.add(sendPanel);

frame.getContentPane().add(background);

frame.pack();

frame.setVisible(true);

}

}

设计过程

服务端使用ServerSocket()类创建一个Socket通信连接,使用accept()方法等待客户端请求。

客户端使用Socket()类,根据指定的IP地址和端口号创建一个到服务端的Socket连接,随后就可以与服务端进行通信。

UI界面主要负责打印客户端和服务端之间发送的消息,显示客户端用户姓名以及消息的发送时间。

效果如下:

Step1: 启动客户端

6b93f2f7e2ba8e4d2c366f0039dff852.png

Step2: 发送问候语句,得到服务器答复

7da00cc50ee172771cd445132b27dc23.png

Step3:发送告别语句,结束Socket连接

481de4fe770223ff7af27721d3af8b6a.png

API调用栈追踪

以服务端为例,设置断点,追踪调用栈,得到如下所示的调用关系:

6bb9d4b0e57ad1c85f07f545062f8304.png

在实例化ServerSocket类的时候,构造函数会调用ServerSocket类的bind()方法,后者会调用继承自抽象类AbstractPlainSocketImpl的PlainSocketImpl的socketBind()方法。在socketBind()中会调用用native关键字标注的bind0()方法。从而实现将一个socket连接绑定到指定的本地IP地址和端口号。

native关键字标注的方法为原生方法,一般是用其他语言写成的函数,常用来实现java语言对操作系统底层接口的访问。JAVA语言本身不能直接对操作系统底层进行操作,但是JAVA允许程序通过JAVA本机接口JNI,使用C/C++等其他语言实现这种操作。

接着,同样的步骤,从ServerSocket类的listen()一直追溯到PlainSocketImpl的socketListen()方法的listen0()。该方法主要为了设置允许的最大连接请求队列长度,当请求队列满时,拒绝后来的连接请求。

最后,同样,从ServerSocket类的accept()追溯到accept0(),等待连接请求的到来。

JAVA Socket接口与LINUX Socket接口对比

作为对比,LINUX提供的相应Socket API分别为:

// 创建一个套接字

int socket(itn domain, int type, int protocol);

// 将套接字绑定到地址上

int bind(int sockfd, const struct sockaddr *addr, socklen_t addelen);

// 监听连接

int listen(int sockfd, int backlog);

// 接收一个连接请求

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

JAVA通过调用这些系统API来实现它的底层功能。不同之处在于,JAVA将这一切全都封装起来,这使得面向网络的编程对于JAVA程序员来说变得十分简单,我们只需要知道使用哪一个类(实际上就是ServerSocket和Socket两个类),为它们传入必要的地址参数,就能够轻松实现Socket通信。

在window操作系统中,使用native标注的本地方法在编译时会生成一个动态链接库(.dll文件)为JAVA语言提供相应的本地服务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值