代码

这是一个带有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);
}
}

设计过程

  1. 服务端使用ServerSocket()类创建一个Socket通信连接,使用accept()方法等待客户端请求。
  2. 客户端使用Socket()类,根据指定的IP地址和端口号创建一个到服务端的Socket连接,随后就可以与服务端进行通信。
  3. UI界面主要负责打印客户端和服务端之间发送的消息,显示客户端用户姓名以及消息的发送时间。

    效果如下:

    Step1: 启动客户端



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



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

API调用栈追踪

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

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

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

接着,同样的步骤,从ServerSocket类的listen()一直追溯到PlainSocketImplsocketListen()方法的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程序员来说变得十分简单,我们只需要知道使用哪一个类(实际上就是ServerSocketSocket两个类),为它们传入必要的地址参数,就能够轻松实现Socket通信。

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

JAVA Socket API与LINUX Socket API探究的更多相关文章

  1. Java实现网络聊天中使用的socket API与Linux socket API之间的关系

    尝试着用Java编写一个网络聊天程序,发现总不如网上写的好,所以就直接引用了网上大神的优秀代码.代码如下: package project1; import java.awt.*; import ja ...

  2. Socket详解-Linux Socket编程(不限Linux)

    “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...

  3. Socket编程实践(2) Socket API 与 简单例程

    在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程.该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端. socket()函 ...

  4. socket套接字TCP API

    socket套接字TCP API socket概念 socket又称"套接字",是计算机网络中进程间通信数据通道的一个端点.或称之为句柄.IP地址+port号就能够唯一确定一个so ...

  5. 理解socket.io(一)---相关的API

    理解socket.io(一)---相关的API 1. 什么是Socket.IO?Socket.IO是node.js的一个模块,它用于浏览器与服务端之间实时通信.它提供了服务器和客户端的组件,只需一个模 ...

  6. Socket编程实践(3) --Socket API

    socket函数 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, ...

  7. Linux socket 编程中存在的五个隐患

    前言:         Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是   开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示如何避免它 ...

  8. linux socket高性能服务器处理框架

    这个博客很多东西 http://blog.csdn.net/luozhonghua2014/article/details/37041765   思考一种高性能的服务器处理框架 1.首先需要一个内存池 ...

  9. Linux socket编程 DNS查询IP地址

    本来是一次计算机网络的实验,但是还没有完全写好,DNS的响应请求报文的冗余信息太多了,不只有IP地址.所以这次的实验主要就是解析DNS报文.同时也需要正确的填充请求报文.如果代码有什么bug,欢迎指正 ...

随机推荐

  1. IT人该如何未雨绸缪,不断提升自己的竞争力?同时尽量避免风险?

    人会慢慢变老,变老后精力,记忆力乃至身体会慢慢变差,这是无法逆转的自然规律.随之会产生的是对中年危机的忧虑乃至恐惧,比如担心能力精力不及年轻人,从而导致收入锐减乃至失业. 对此我有如下三点不解.第一, ...

  2. [ch03-02] 交叉熵损失函数

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 3.2 交叉熵损失函数 交叉熵(Cross Entrop ...

  3. 解密面试中的套路,你都get到了么?

    如果大家有关注一些测试类的公众号或者论坛的话,肯定会发现很多文章都在表示现在行业的寒冬冷潮来了!然后有很多测试行业从业者,或者转行测试行业者都表示:工作好难找,公司跑了千千万,依然拿不到一个offer ...

  4. Mac OS 终端利器 iTerm2(怕以后找不到,自存自用)

    之前一直使用 Mac OS 自带的终端,用起来虽然有些不太方便,但总体来说还是可以接受的,是有想换个终端的想法,然后今天偶然看到一个终端利器 iTerm2,发现真的很强大,也非常的好用,按照网上配置了 ...

  5. 【漏洞复现】Apache Solr远程代码执行(CVE-2019-0193)

    0x01 概述 Solr简介 Apache Solr 是一个开源的企业级搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.Apache Solr ...

  6. SQL语句实用技巧1

    --显示行号 select *, ROW_NUMBER() OVER(Order by TYPENAME ) AS RowNumber from ( select distinct TYPENAME ...

  7. 高并发编程-CountDownLatch深入解析

    要点解说 CountDownLatch允许一个或者多个线程一直等待,直到一组其它操作执行完成.在使用CountDownLatch时,需要指定一个整数值,此值是线程将要等待的操作数.当某个线程为了要执行 ...

  8. Linux中docker的使用二

    容器下安装jdk和tomcat:通过挂载文件的方法,把宿主机上的文件挂载到容器中,然后解压到opt目录下:tar -zxvf 包名 -C /opt//opt目录下drwxr-xr-x 8 10 143 ...

  9. 什么是WCF

    WCF的全称是windows的通信基础 Windows Communication Foundation.本质上来讲,他是一套软件开发包. 服务终节点的三要素 用来发送接收消息的构造 创建一个WCF程 ...

  10. PAT甲级满分攻略|记一次考试经历

    一次考试经历 今天是"大雪",很冷. 来到隔壁的学校考试,记得上一次来河中医是两年前大一刚开学吧,那天晚上印象比较深刻,6个室友骑车到处闲逛.当时还不会Hello world. 很 ...