本文目录一览:
疯狂Java讲义:使用ServletSocket创建TCP服务器端
使用ServletSocket创建TCP服务器端
从图 中看上去TCP通信的两个通信实体之间并没有服务器端 客户端之分 但那是两个通信实体已经建立虚拟链路之后的示意图 在两个通信实体没有建立虚拟链路之前 必须有一个通信实体先做出 主动姿态 主动接收来自其他通信实体的连接请求
Java中能接受其他通信实体连接请求的类是ServerSocket
。ServerSocket
对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待状态。ServerSocket
包含一个监听来自客户端连接请求的方法:
Socket accept()
如果接收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket(如图 所示每个TCP连接有两个Socket),否则该方法将一直处于等待状态,线程也被阻塞。
为了创建ServerSocket
对象,ServerSocket
类提供了如下几个构造器:
ServerSocket(int port)
:用指定的端口port
来创建一个ServerSocket
,该端口应该是有一个有效的端口整数值(1~65535)。ServerSocket(int port, int backlog)
:增加一个用来改变连接队列长度的参数backlog
。ServerSocket(int port, int backlog, InetAddress localAddr)
:在机器存在多个IP地址的情况下,允许通过localAddr
这个参数来指定将ServerSocket
绑定到指定的IP地址。 当ServerSocket
使用完毕,应使用ServerSocket
的close()
方法来关闭该ServerSocket
。通常情况下,服务器不应该只接受一个客户端请求,而应该不断地接受来自客户端的所有请求,所以Java程序通常会通过循环,不断调用ServerSocket
的accept()
方法,如下代码片段所示:
// 创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket ss = new ServerSocket(8080);
// 采用循环不断接受来自客户端的请求
while (true) {
// 每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
Socket s = ss.accept();
// 下面就可以使用Socket进行通信了
...
}
上面程序中创建ServerSocket
没有指定IP地址,则该ServerSocket
将会绑定到本机默认的IP地址。程序中使用8080作为该ServerSocket
的端口号,通常推荐使用1024以上的端口,主要是为了避免与其他应用程序的通用端口冲突。
求推荐JAVA入门书籍
- 《Head First Java》
《Head First Java》是本完整的面向对象(object-oriented,OO)程序设计和Java的学习指导。此书是根据学习理论所设计的,让你可以从学习程序语言的基础开始一直到包括线程、网络与分布式程序等项目。最重要的,你会学会如何像个面向对象开发者一样去思考。 《HeadFirstJava(中文版)(第2版)(涵盖Java5.0)》的图文并茂学习方式能让你快速地在脑海中掌握住知识。敞开心胸准备好学习这些关键性的主题:Java程序语言;面向对象程序开发;Swing图形化接口;使用JavaAPI函数库;编写、测试与部署应用程序;处理异常;多线程;网络程序设计;集合与泛型。 如果你想要看"一本正经"的书,去找其他的。如果你真地想要好好地学习Java,你会需要《Head First Java》。这本书可是Amazon编辑推荐的十大好书之一!强烈推荐学习此书,非常适合初学者入门。 - 《Java从入门到精通》
《Java从入门到精通》这本书主要针对Java基础,对于没有学过Java的人才说,是一个不错的选择。通过这本书,大家可以从零开始,慢慢来学习,而且实操很多,不会让你看到最后出现只会理论的情况。为什么说培训的人不用看呢?因为这本书上的内容和许多培训机构的书籍有很多重复的地方,所以参加培训的同学就可以不看了。如果觉得自学太难太慢的话,那就报培训机构吧。 - 《Thinking in Java》(中文名:《Java编程思想》)
《Java编程思想》可以说是最经典的Java著作,是所有Java程序员必备教科书。这本书不管是正在学习还是已经工作许多年的程序员,都可以从这本书中得到你想要的东西。这本书具有教材和工具书的作用,就像一本字典,想知道什么都可以从中查询。虽然这本书很好,但并不建议初学者学习,对于初学者难度较大。 - 《疯狂Java讲义》
《疯狂的讲义》这本书比较适合自学者,内容比较项目化,实操方法很多,如果你想进行Java的深入学习,不妨看看这本书。 《疯狂Java讲义(第5版)》深入介绍了Java编程的相关方面,全书内容覆盖了Java的基本语法结构、Java的面向对象特征、Java集合框架体系、Java泛型、异常处理、Java GUI编程、JDBC数据库编程、Java注释、Java的IO流体系、Java多线程编程、Java网络通信编程和Java反射机制。覆盖了java.lang
、java.util
、java.text
、和java.nio
、java.sql
、java.awt
、javax.swing
包下绝大部分类和接口。本书重点介绍了Java的模块化系统,还详细介绍了Java 10、Java 11的使用var
声明局部变量、在Lambda表达式中使用var
声明变量、改进的javac
命令、基于嵌套的访问控制、HTTP Client网络编程,以及Java 10、Java 11新增的各种API功能。 - 《Java核心技术》
这本书分为两个部分,第一个部分讲的是基础知识,第二个部分讲的是高级特性。由于内容非常有层次,所以非常适合自学和上培训机构的同学学习。尤其对参加培训的同学作用较大,因为一般培训机构讲的非常快,有很多东西没办法及时消化吸收,很多基础和核心的东西就会掌握的不牢固,那么这本书正好弥补了这个缺失。 - 《Java开发实战经典》
该书是一本综合讲解Java核心技术的书籍,在书中使用大量的代码及案例进行知识点的分析与运用,并且给出一些比较成熟的开发步骤,帮助读者更好地进行Java的开发。 从作者多年的Java培训经验来看,大部分学生对各种高端开发都没有任何问题,唯一的问题在于Java基础并不牢固,而且在国内也始终没有一本真正可以引领读者入门的好书籍,大部分的书籍都是围绕概念本身进行讲解的,没有讲解清楚为什么要具备这些知识以及该如何去理解这些知识。本书真正地做到了让每一位读者都能清楚地知道每个知识点的来龙去脉,不仅可以很容易地看懂一个程序,而且能真正地灵活运用程序,编写代码。 在学习编程语言时,环境、代码调试等,都是很多读者最头疼的地方,而且很多代码都会存在一些细节上的问题,所以,本书为了让读者可以更好地理解每一个知识点,将书中所有内容都录制成了视频,让每一位读者真正做到"轻松学Java、从零开始学Java",以优质的视频教学为每一位读者提供最大的支持。 这本书比较适合自学者学习,里面有很多小案例,可以边学边练,巩固知识。
疯狂Java讲义:使用MulticastSocket实现多点广播(4)
该类主要实现底层的网络通信功能。在该类中提供了一个broadCast
方法,该方法使用MulticastSocket
将指定字符串广播到所有客户端。还提供了sendSingle
方法,该方法使用DatagramSocket
将指定字符串发送到指定SocketAddress
,如程序中前两行粗体字代码所示。除此之外,该类里还提供了两个内部线程类ReadSingle
和ReadBroad
,这两个线程类采用循环不断读取DatagramSocket
和MulticastSocket
中的数据。如果读到的信息是广播来的在线信息,则保持该用户在线;如果读到的是用户的聊天信息,则直接将该信息显示出来。
在该类中用到了本程序的一个主类LanChat
,该类使用DefaultListModel
来维护用户列表,该类里的每个列表项就是一个UserInfo
。该类还提供了一个ImageCellRenderer
,该类用于将列表项绘制出用户图标和用户名字。
程序清单:LanChat.java
public class LanChat extends JFrame {
private DefaultListModel listModel = new DefaultListModel();
// 定义一个JList对象
private JList friendsList = new JList(listModel);
// 定义一个用于格式化日期的格式器
private DateFormat formatter = DateFormat.getDateTimeInstance();
public LanChat() {
super("局域网聊天");
// 设置该JList使用ImageCellRenderer作为单元格绘制器
friendsList.setCellRenderer(new ImageCellRenderer());
listModel.addElement(new UserInfo("all", "所有人", null));
friendsList.addMouseListener(new ChangeMusicListener());
add(new JScrollPane(friendsList));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 400, 300);
}
// 向用户列表中添加用户
public void addUser(UserInfo user) {
listModel.addElement(user);
}
// 从用户列表中删除用户
public void removeUser(int pos) {
listModel.removeElementAt(pos);
}
// 根据地址来查询用户
public UserInfo getUserBySocketAddress(SocketAddress address) {
for (int i = 0; i < getUserNum(); i++) {
UserInfo user = getUser(i);
if (user.getAddress() != null && user.getAddress().equals(address)) {
return user;
}
}
return null;
}
// 下面两个方法是对ListModel的包装
// 获取该聊天窗口的用户数量
public int getUserNum() {
return listModel.size();
}
// 获取指定位置的用户
public UserInfo getUser(int pos) {
return (UserInfo) listModel.elementAt(pos);
}
// 实现JList上的鼠标双击监听器
class ChangeMusicListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
// 如果鼠标的击键次数大于
if (e.getClickCount() >= 2) {
// 取出鼠标双击时选中的列表项
UserInfo user = (UserInfo) friendsList.getSelectedValue();
// 如果该列表项对应用户的交谈窗口为null
if (user.getChatFrame() == null) {
// 为该用户创建一个交谈窗口,并让该用户引用该窗口
user.setChatFrame(new ChatFrame(null, user));
}
// 如果该用户的窗口没有显示,则让该用户的窗口显示出来
if (!user.getChatFrame().isShowing()) {
user.getChatFrame().setVisible(true);
}
}
}
}
/**
* 处理网络数据报,该方法将根据聊天信息得到聊天者
* 并将信息显示在聊天对话框中
* @param packet 需要处理的数据报
* @param single 该信息是否为私聊信息
*/
public void processMsg(DatagramPacket packet, boolean single) {
// 获取该发送该数据报的SocketAddress
InetSocketAddress srcAddress = (InetSocketAddress) packet.getSocketAddress();
// 如果是私聊信息,则该Packet获取的是DatagramSocket的地址,将端口减1才是
// 对应的MulticastSocket的地址
if (single) {
srcAddress = new InetSocketAddress(srcAddress.getHostName(), srcAddress.getPort() - 1);
}
UserInfo srcUser = getUserBySocketAddress(srcAddress);
if (srcUser != null) {
// 确定消息将要显示到哪个用户对应窗口上
UserInfo alertUser = single ? srcUser : getUser(0);
// 如果该用户对应的窗口为空,显示该窗口
if (alertUser.getChatFrame() == null) {
alertUser.setChatFrame(new ChatFrame(null, alertUser));
}
// 定义添加的提示信息
String tipMsg = single ? "对您说" : "对大家说";
// 显示提示信息
alertUser.getChatFrame().addString(srcUser.getName() + tipMsg
+ "……(" + formatter.format(new Date()) + ")\n"
+ new String(packet.getData(), 0, packet.getLength()) + "\n");
if (!alertUser.getChatFrame().isShowing()) {
alertUser.getChatFrame().setVisible(true);
}
}
}
// 主方法,程序的入口
public static void main(String[] args) {
LanChat lc = new LanChat();
new LoginFrame(lc, "请输入用户名、头像后登录");
}
}
// 定义用于改变JList列表项外观的类
class ImageCellRenderer extends JPanel implements ListCellRenderer {
private ImageIcon icon;
private String name;
// 定义绘制单元格时的背景色
private Color background;
// 定义绘制单元格时的前景色
private Color foreground;
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
UserInfo userInfo = (UserInfo) value;
icon = new ImageIcon("ico/" + userInfo.getIcon() + ".gif");
name = userInfo.getName();
background = isSelected ? list.getSelectionBackground() : list.getBackground();
foreground = isSelected ? list.getSelectionForeground() : list.getForeground();
// 返回该JPanel对象作为单元格绘制器
return this;
}
// 重写paintComponent方法,改变JPanel的外观
public void paintComponent(Graphics g) {
int imageWidth = icon.getImage().getWidth(null);
int imageHeight = icon.getImage().getHeight(null);
g.setColor(background);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(foreground);
// 绘制好友图标
g.drawImage(icon.getImage(), getWidth() / 2 - imageWidth / 2, 0, null);
g.setFont(new Font("SansSerif", Font.BOLD, 14));
// 绘制好友用户名
g.drawString(name, getWidth() / 2 - name.length() * imageHeight / 2, imageHeight + 10);
}
// 通过该方法来设置该ImageCellRenderer的最佳大小
public Dimension getPreferredSize() {
return new Dimension(100, 50);
}
}
上面类中提供的addUser
和removeUser
方法用于暴露给通信类ComUtil
使用,用于向用户列表中添加、删除用户。除此之外,该类还提供了一个processMsg
方法,该方法用于处理网络中读取的数据报,将数据报中的内容取出,并显示在特定的窗口中。
上面讲解的只是本程序的关键类。本程序还涉及YeekuProtocol
、ChatFrame
、LoginFrame
等类。由于篇幅关系,此处不再给出这些类的源代码,读者可以参考codes/.../LanTalk
路径下的源代码。
疯狂java讲义学完什么水平
疯狂java讲义学完中等水平。疯狂java讲义是国人原创必读经典了,同样非常适合初学者。讲解内容细致全面,系统通俗,目录划分和查找非常方便,就算完全没有基础也可以学的没有什么压力,学完可以升级一个水平,达到中等水平。