疯狂java讲义
① 疯狂java讲义:使用DatagramSocket发送、接收数据[2]
程序客户端代码也与此类似 客户端采用循环不断地读取用户键盘输入 每当读到用户输入内容后就将该内容封装成DatagramPacket数据报 再将该数据报发送出去 接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中) 客户端代码如下
程序清单 codes/ / /UdpClient java
public class UdpClient
{
//定义发送数据报的目的地
public static final int DEST_PORT = ;
public static final String DEST_IP = ;
//定义每个数据报的最大大小为 K
private static final int DATA_LEN = ;
//定义该客户端使用的DatagramSocket
private DatagramSocket socket = null;
//定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
//以指定字节数组创建准备接受数据的DatagramPacket对象
private DatagramPacket inPacket =
new DatagramPacket(inBuff inBuff length)
//定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
public void init()throws IOException
{
try
{
//创建一个客户端DatagramSocket 使用随机端口
socket = new DatagramSocket()
//初始化发送用的DatagramSocket 它包含一个长度为 的字节数组
outPacket = new DatagramPacket(new byte[ ]
InetAddress getByName(DEST_IP) DEST_PORT)
//创建键盘输入流
Scanner scan = new Scanner(System in)
//不断读取键盘输入
while(scan hasNextLine())
{
//将键盘输入的一行字符串转换字节数组
byte[] buff = scan nextLine() getBytes()
//设置发送用的DatagramPacket里的字节数据
outPacket setData(buff)
//发送数据报
socket send(outPacket)
//读取Socket中的数据 读到的数据放在inPacket所封装的字节数组里
socket receive(inPacket)
System out println(new String(inBuff
inPacket getLength()))
}
}
//使用finally块保证关闭资源
finally
{
if (socket != null)
{
socket close()
}
}
}
public static void main(String[] args)
throws IOException
{
new UdpClient() init()
}
}
上面程序的粗体字代码同样也是通过DatagramSocket发送 接收DatagramPacket的关键代码 这些代码与服务器的代码基本相似 而客户端与服务器端的唯一区别在于 服务器所在IP地址 端口是固定的 所以客户端可以直接将该数据报发送给服务器 而服务器则需要根据接收到的数据报来决定将 反馈 数据报的目的地
读者可能会发现 使用DatagramSocket进行网络通信时 服务器端无须 也无法保存每个客户端的状态 客户端把数据报发送到服务器后 完全有可能立即退出 但不管客户端是否退出 服务器无法知道客户端的状态
当使用UDP协议时 如果想让一个客户端发送的聊天信息可被转发到其他所有客户端则比较困难 可以考虑在服务器使用Set来保存所有客户端信息 每当接收到一个客户端的数据报之后 程序检查该数据报的源SocketAddress是否在Set集合中 如果不在就将该SocketAddress添加到该Set集合中 但这样一来又涉及一个问题 可能有些客户端发送一个数据报之后永久性地退出了程序 但服务器端还将该客户端的SocketAddress保存在Set集合中……总之 这种方式需要处理的问题比较多 编程比较烦琐 幸好Java为UDP协议提供了MulticastSocket类 通过该类可以轻松实现多点广播
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
Java程序设计培训视频教程
lishixin/Article/program/Java/hx/201311/27260
② 疯狂Java讲义:使用Socket进行通信[2]
程序清单 codes/ / /Client java
public class Client
{
public static void main(String[] args)
throws IOException
{
Socket socket = new Socket( )
//将Socket对应的输入流包装成BufferedReader
BufferedReader br = new BufferedReader(
new InputStreamReader(socket getInputStream()))
//进行普通IO操作
String line = br readLine()
System out println( 来自服务器的数据 + line)
//关闭输入流 socket
br close()
socket close()
}
}
上面程序中粗体字代码是使用ServerSocket和Socket建立网络连接的代码 斜体字代码是通过Socket获取输入流 输出流进行通信的代码 通过程序不难看出 一旦使用ServerSocket Socket建立网络连接之后 程序通过网络通信与普通IO并没有太大的区别
先运行上面程序中的Server类 将看到服务器一直处于等待状态 因为服务器使用了死循环来接受来自客户端的请求 再运行Client类 将可看到程序输出 来自服务器的数据 您好 您收到了服务器的新年祝福! 这表明客户端和服务器端通信成功
上面程序为了突出通过ServerSocket和Socket建立连接 并通过底层IO流进行通信的主题 程序没有进行异常处理 也没有使用finally块来关闭资源
实际应用中 程序可能不想让执行网络连接 读取服务器数据的进程一直阻塞 而是希望当网络连接 读取操作超过合理时间之后 系统自动认为该操作失败 这个合理时间就是超时时长 Socket对象提供了一个setSoTimeout(int timeout)来设置超时时长 如下的代码片段所示
Socket s = new Socket( )
//设置 秒之后即认为超时
s setSoTimeout( )
当我们为Socket对象指定了超时时长之后 如果在使用Socket进行读 写操作完成之前已经超出了该时间限制 那么这些方法就会抛出SocketTimeoutException异常 程序可以对该异常进行捕捉 并进行适当处理 如下代码所示
try
{
//使用Scanner来读取网络输入流中的数据
Scanner scan = new Scanner(s getInputStream())
//读取一行字符
String line = scan nextLine()
…
}
//捕捉SocketTimeoutException异常
catch(SocketTimeoutException ex)
{
//对异常进行处理
…
}
假设程序需要为Socket连接服务器时指定超时时长 即经过指定时间后 如果该Socket还未连接到远程服务器 则系统认为该Socket连接超时 但Socket的所有构造器里都没有提供指定超时时长的参数 所以程序应该先创建一个无连接的Socket 再调用Socket的connect()方法来连接远程服务器 而connect方法就可以接受一个超时时长参数 如下代码所示
//创建一个无连接的Socket
Socket s = new Socket()
//让该Socket连接到远程服务器 如果经过 秒还没有连接到 则认为连接超时
s connconnect(new InetAddress(host port) )
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
Java程序设计培训视频教程
lishixin/Article/program/Java/hx/201311/27265
③ 疯狂java讲义学完什么水平
疯狂java讲义学完中等水平。疯狂java讲义是国人原创必读经典了,同样非常适合初学者。讲解内容细致全面,系统通俗,目录划分和查找非常方便,就算完全没有基础也可以学的没有什么压力,学完可以升级一个水平,达到中等水平。
④ 推荐几本安卓开发的书籍,我学过一点点java,也算有点java基础的
最好的java学习,最全的java学习
《疯狂Java讲义》---本书并不是一本简单的Java入门教材,也不是一门“闭门造车”式的Java读物。本书来自于笔者6年多的Java培训经历,凝结了笔者近6000个小时的授课经验,总结了上千个Java学员学习过程中的典型错误。
《疯狂Android讲义》---本书全面地介绍了Android应用开发的相关知识。
《轻量级Java EE企业应用实战--Struts 2+Spring+Hibernate整合开发》---本书是《轻量级Java EE企业应用实战》的第3版,第3版保持了第2版内容全面、深入的特点,主要完成全部知识的升级。
《 疯狂Java 突破程序员基本功16课》、《疯狂XML讲义》、《疯狂Ajax讲义Prototype/jQuery+DWR+Spring+Hibernate整合开发》、《Struts 2.1权威指南--基于WebWork核心的MVC开发》、《经典Java EE企业应用实战》
《疯狂HTML 5/CSS 3/JavaScript讲义》 --- 本书是一本全面介绍HTML5、CSS 3和JavaScript前端开发技术的图书,本书系统地介绍了HTML 5常用的元素和属性,HTML 5的表单元素和属性,HTML 5的绘图支持,HTML 5的多媒体支持,CSS 3的功能和用法、包括最前沿的变形与动画功能等。配合‘疯狂java’官网上的视频学习。“李刚老师视频”、“肖文吉老师视频”“李韩飞老师视频”
⑤ 疯狂Java讲义的源码如何导入eclipse运行
Java项目的源代码通过一下四部完成导入到eclipse
1、单击eclipse的file菜单 ,选择 import project from file system
2、在弹出的窗口单击 diretory 按钮 选择Java源代码文件系统所在的目录
3、单击“选择文件夹 ”完成将java源代码导入到eclispe系统
你明白了吗?
⑥ 疯狂Java讲义:使用MulticastSocket实现多点广播(4)
该类主要实现底层的网络通信功能 在该类中提供了一个broadCast方法 该方法使用MulticastSocket将指定字符串广播到所有客户端 还提供了sendSingle方法 该方法使用DatagramSocket将指定字符串发送到指定SocketAddress 如程序中前两行粗体字代码所示 除此之外 该类里还提供了 个内部线程类 ReadSingle和ReadBroad 这两个线程类采用循环不断读取DatagramSocket和MulticastSocket中的数据 如果读到的信息是广播来的在线信息 则保持该用户在线 如果读到的是用户的聊天信息 则直接将该信息显示出来
在该类中用到了本程序的一个主类 LanChat 该类使用DefaultListModel来维护用户列表 该类里的每个列表项就是一个UserInfo 该类还提供了一个ImageCellRenderer 该类用于将列表项绘制出用户图标和用户名字
程序清单 codes/ / /LanChat/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( )
}
//向用户列表中添加用户
public void addUser(UserInfo user)
{
listModel addElement(user)
}
//从用户列表中删除用户
public void removeUser(int pos)
{
listModel removeElementAt(pos)
}
//根据地址来查询用户
public UserInfo getUserBySocketAddress(SocketAddress address)
{
for (int i = ; 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() >= )
{
//取出鼠标双击时选中的列表项
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 getSocket
Address()
//如果是私聊信息 则该Packet获取的是DatagramSocket的地址 将端口减 才是
//对应的MulticastSocket的地址
if (single)
{
srcAddress = new InetSocketAddress(srcAddress getHostName()
srcAddress getPort() )
}
UserInfo srcUser = getUserBySocketAddress(srcAddress)
if (srcUser != null)
{
//确定消息将要显示到哪个用户对应窗口上
UserInfo alertUser = single ? srcUser : getUser( )
//如果该用户对应的窗口为空 显示该窗口
if (alertUser getChatFrame() == null)
{
alertUser setChatFrame(new ChatFrame(null alertUser))
}
//定义添加的提示信息
String tipMsg = single ? 对您说 : 对大家说 ;
//显示提示信息
alertUser getChatFrame() addString(srcUser getName() + tipMsg
+ ……( + formatter format(new Date()) + )
+ new String(packet getData() packet getLength()) + )
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 getBack
ground()
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( getWidth() getHeight())
g setColor(foreground)
//绘制好友图标
g drawImage(icon getImage() getWidth() / imageWidth / null)
g setFont(new Font( SansSerif Font BOLD ))
//绘制好友用户名
g drawString(name getWidth() / name length() * imageHeight + )
}
//通过该方法来设置该ImageCellRenderer的最佳大小
public Dimension getPreferredSize()
{
return new Dimension( )
}
}
上面类中提供的addUser和removeUser方法用于暴露给通信类ComUtil使用 用于向用户列表中添加 删除用户 除此之外 该类还提供了一个processMsg方法 该方法用于处理网络中读取的数据报 将数据报中的内容取出 并显示在特定的窗口中
上面讲解的只是本程序的关键类 本程序还涉及YeekuProtocol ChatFrame LoginFrame等类 由于篇幅关系 此处不再给出这些类的源代码 读者可以参考codes/ / /LanTalk路径下的源代码
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
lishixin/Article/program/Java/hx/201311/27255
⑦ 大家觉得初学者《疯狂Java讲义》怎么样
我见过特好的一本书,很值得买。全书大概有800页,javase的知识都涉及到,部分内容对新手有难度,没有编程基础不建议看。而且也不适合只想过java二级的,只适合打算在java领域深造的人群。至于大神的话,不用看se的书了吧。