服务端

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Windows.Forms;
  12.  
  13. namespace SocketServer
  14. {
  15. public partial class Form1 : Form
  16. {
  17. /// <summary>
  18. /// 保存连接的所有用户
  19. /// </summary>
  20. private List<User> userList = new List<User>();
  21.  
  22. /// <summary>
  23. /// 服务器IP地址
  24. /// </summary>;
  25. private string ServerIP;
  26.  
  27. /// <summary>
  28. /// 监听端口
  29. /// </summary>
  30. private int port;
  31. private TcpListener myListener;
  32.  
  33. /// <summary>
  34. /// 是否正常退出所有接收线程
  35. /// </summary>
  36. bool isNormalExit = false;
  37.  
  38. public Form1()
  39. {
  40. InitializeComponent();
  41. btn_Stop.Enabled = false;
  42. SetServerIPAndPort();
  43. }
  44.  
  45. /// <summary>
  46. /// 根据当前程序目录的文本文件‘ServerIPAndPort.txt’内容来设定IP和端口
  47. /// 格式:127.0.0.1:8885
  48. /// </summary>
  49. private void SetServerIPAndPort()
  50. {
  51. FileStream fs = new FileStream("ServerIPAndPort.txt", FileMode.Open);
  52. StreamReader sr = new StreamReader(fs);
  53. string IPAndPort = sr.ReadLine();
  54. ServerIP = IPAndPort.Split(':')[]; //设定IP
  55. port = int.Parse(IPAndPort.Split(':')[]); //设定端口
  56. sr.Close();
  57. fs.Close();
  58. }
  59.  
  60. /// <summary>
  61. /// 开始监听
  62. /// </summary>
  63. /// <param name="sender"></param>
  64. /// <param name="e"></param>
  65. private void btn_Start_Click(object sender, EventArgs e)
  66. {
  67. ListenClient();
  68. }
  69.  
  70. /// <summary>
  71. /// 开始服务,监听客户端
  72. /// </summary>
  73. private void ListenClient()
  74. {
  75. myListener = new TcpListener(IPAddress.Parse(ServerIP), port);
  76. myListener.Start();
  77. AddTalkMessage(string.Format("开始在{0}:{1}监听客户连接", ServerIP, port));
  78. //创建一个线程监客户端连接请求
  79. Thread myThread = new Thread(ListenClientConnect);
  80. myThread.Start();
  81. btn_Start.Enabled = false;
  82. btn_Stop.Enabled = true;
  83. }
  84.  
  85. /// <summary>
  86. /// 接收客户端连接
  87. /// </summary>
  88. private void ListenClientConnect()
  89. {
  90. TcpClient newClient = null;
  91. while (true)
  92. {
  93. try
  94. {
  95. newClient = myListener.AcceptTcpClient();
  96. }
  97. catch
  98. {
  99. //当单击‘停止监听’或者退出此窗体时 AcceptTcpClient() 会产生异常
  100. //因此可以利用此异常退出循环
  101. break;
  102. }
  103. //每接收一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息;
  104. User user = new User(newClient);
  105. Thread threadReceive = new Thread(ReceiveData);
  106. threadReceive.Start(user);
  107. userList.Add(user);
  108. AddTalkMessage(string.Format("[{0}]进入", newClient.Client.RemoteEndPoint));
  109. AddTalkMessage(string.Format("当前连接用户数:{0}", userList.Count));
  110. }
  111.  
  112. }
  113.  
  114. /// <summary>
  115. /// 处理接收的客户端信息
  116. /// </summary>
  117. /// <param name="userState">客户端信息</param>
  118. private void ReceiveData(object userState)
  119. {
  120. User user = (User)userState;
  121. TcpClient client = user.client;
  122. while (isNormalExit == false)
  123. {
  124. string receiveString = null;
  125. try
  126. {
  127. //从网络流中读出字符串,此方法会自动判断字符串长度前缀
  128. receiveString = user.br.ReadString();
  129. }
  130. catch (Exception)
  131. {
  132. if (isNormalExit == false)
  133. {
  134. AddTalkMessage(string.Format("与[{0}]失去联系,已终止接收该用户信息", client.Client.RemoteEndPoint));
  135. RemoveUser(user);
  136. }
  137. break;
  138. }
  139. AddTalkMessage(string.Format("来自[{0}]:{1}", user.client.Client.RemoteEndPoint, receiveString));
  140. string[] splitString = receiveString.Split(',');
  141. switch (splitString[])
  142. {
  143. case "Login":
  144. user.userName = splitString[];
  145. SendToAllClient(user, receiveString);
  146. break;
  147. case "Logout":
  148. SendToAllClient(user, receiveString);
  149. RemoveUser(user);
  150. return;
  151. case "AllTalk":
  152. string allTalkString = receiveString.Substring(splitString[].Length + splitString[].Length + );
  153. AddTalkMessage(string.Format("{0}说:{1}", user.userName, allTalkString));
  154. for (int i = ; i < userList.Count; i++)
  155. {
  156. SendToClient(userList[i], "talk," + user.userName + "," + allTalkString);
  157. }
  158. break;
  159. case "Talk":
  160. string talkString = receiveString.Substring(splitString[].Length + splitString[].Length + );
  161. AddTalkMessage(string.Format("{0}对{1}说:{2}", user.userName, splitString[], talkString));
  162. SendToClient(user, "talk," + "你对"+ splitString[] + "说," + talkString);//发给自己
  163. foreach (User target in userList)//发给对方
  164. {
  165. if (target.userName == splitString[] && user.userName != splitString[])
  166. {
  167. SendToClient(target, "talk," + user.userName + "对你说," + talkString);
  168. break;
  169. }
  170. }
  171. break;
  172. default:
  173. AddTalkMessage("错误:" + receiveString);
  174. break;
  175. }
  176. }
  177. }
  178.  
  179. /// <summary>
  180. /// 发送消息给所有客户
  181. /// </summary>
  182. /// <param name="user">指定发给哪个用户</param>
  183. /// <param name="message">信息内容</param>
  184. private void SendToAllClient(User user, string message)
  185. {
  186. string command = message.Split(',')[].ToLower();
  187. if (command == "login")
  188. {
  189. //获取所有客户端在线信息到当前登录用户
  190. for (int i = ; i < userList.Count; i++)
  191. {
  192. SendToClient(user, "login," + userList[i].userName);
  193. }
  194. //把自己上线,发送给所有客户端
  195. for (int i = ; i < userList.Count; i++)
  196. {
  197. if (user.userName != userList[i].userName)
  198. {
  199. SendToClient(userList[i], "login," + user.userName);
  200. SendToClient(userList[i], "talk,服务器:" + user.userName + "已上线,");
  201. }
  202. }
  203. }
  204. else if (command == "logout")
  205. {
  206. for (int i = ; i < userList.Count; i++)
  207. {
  208. if (userList[i].userName != user.userName)
  209. {
  210. SendToClient(userList[i], message);
  211. SendToClient(userList[i], "talk,服务器:" + user.userName + "已下线,");
  212. }
  213. }
  214. }
  215. }
  216.  
  217. /// <summary>
  218. /// 发送 message 给 user
  219. /// </summary>
  220. /// <param name="user">指定发给哪个用户</param>
  221. /// <param name="message">信息内容</param>
  222. private void SendToClient(User user, string message)
  223. {
  224. try
  225. {
  226. //将字符串写入网络流,此方法会自动附加字符串长度前缀
  227. user.bw.Write(message);
  228. user.bw.Flush();
  229. AddTalkMessage(string.Format("向[{0}]发送:{1}", user.userName, message));
  230. }
  231. catch
  232. {
  233. AddTalkMessage(string.Format("向[{0}]发送信息失败", user.userName));
  234. }
  235. }
  236.  
  237. /// <summary>
  238. /// 移除用户
  239. /// </summary>
  240. /// <param name="user">指定要移除的用户</param>
  241. private void RemoveUser(User user)
  242. {
  243. userList.Remove(user);
  244. user.Close();
  245. AddTalkMessage(string.Format("当前连接用户数:{0}", userList.Count));
  246. }
  247.  
  248. private delegate void AddTalkMessageDelegate(string message);
  249. /// <summary>
  250. /// 在聊天对话框(txt_Message)中追加聊天信息
  251. /// </summary>
  252. /// <param name="str">要追加的信息</param>
  253. private void AddTalkMessage(string message)
  254. {
  255. if (txt_Message.InvokeRequired)
  256. {
  257. AddTalkMessageDelegate d = new AddTalkMessageDelegate(AddTalkMessage);
  258. txt_Message.Invoke(d, new object[] { message });
  259. }
  260. else
  261. {
  262. txt_Message.AppendText(message + Environment.NewLine);
  263. txt_Message.ScrollToCaret();
  264. }
  265. }
  266.  
  267. /// <summary>
  268. /// 停止监听
  269. /// </summary>
  270. /// <param name="sender"></param>
  271. /// <param name="e"></param>
  272. private void btn_Stop_Click(object sender, EventArgs e)
  273. {
  274. stopListen();
  275. }
  276.  
  277. private void stopListen()
  278. {
  279. AddTalkMessage("开始停止服务,并依次使用户退出!");
  280. isNormalExit = true;
  281. for (int i = userList.Count - ; i >= ; i--)
  282. {
  283. RemoveUser(userList[i]);
  284. }
  285. //通过停止监听让 myListener.AcceptTcpClient() 产生异常退出监听线程
  286. myListener.Stop();
  287. btn_Start.Enabled = true;
  288. btn_Stop.Enabled = false;
  289. }
  290.  
  291. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  292. {
  293. if (myListener != null)
  294. stopListen();//btn_Stop.PerformClick(); //引发 btn_Stop 的Click事件
  295. }
  296.  
  297. private void btn_send_Click(object sender, EventArgs e)
  298. {
  299. for (int i = ; i < userList.Count; i++)
  300. {
  301. SendToClient(userList[i], "talk,服务器," + talk.Text + "\r\n");
  302. }
  303. talk.Clear();
  304. }
  305.  
  306. private void talk_KeyPress(object sender, KeyPressEventArgs e)
  307. {
  308. if (e.KeyChar == (char)Keys.Return)
  309. {
  310. //触发【发送】按钮的单击事件
  311. btn_send.PerformClick();
  312. }
  313. }
  314.  
  315. }
  316. }
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net.Sockets;
  5. using System.IO;
  6.  
  7. namespace SocketServer
  8. {
  9. class User
  10. {
  11. public TcpClient client { get; private set; }
  12. public BinaryReader br { get; private set; }
  13. public BinaryWriter bw { get; private set; }
  14. public string userName { get; set; }
  15.  
  16. public User(TcpClient client)
  17. {
  18. this.client = client;
  19. NetworkStream networkStream = client.GetStream();
  20. br = new BinaryReader(networkStream);
  21. bw = new BinaryWriter(networkStream);
  22. }
  23.  
  24. public void Close()
  25. {
  26. br.Close();
  27. bw.Close();
  28. client.Close();
  29. }
  30.  
  31. }
  32. }

客户端

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Windows.Forms;
  12.  
  13. namespace SocketClient
  14. {
  15. public partial class Form1 : Form
  16. {
  17. private string ServerIP; //IP
  18. private int port; //端口
  19. private bool isExit = false;
  20. private TcpClient client;
  21. private BinaryReader br;
  22. private BinaryWriter bw;
  23.  
  24. public Form1()
  25. {
  26. InitializeComponent();
  27. Random r = new Random((int)DateTime.Now.Ticks);
  28. txt_UserName.Text = "user" + r.Next(, );
  29. lst_OnlineUser.HorizontalScrollbar = true;
  30. lst_OnlineUser.Items.Add("所有人");
  31. lst_OnlineUser.SelectedIndex = ;
  32. SetServerIPAndPort();
  33. }
  34.  
  35. /// <summary>
  36. /// 根据当前程序目录的文本文件‘ServerIPAndPort.txt’内容来设定IP和端口
  37. /// 格式:127.0.0.1:8885
  38. /// </summary>
  39. private void SetServerIPAndPort()
  40. {
  41. try
  42. {
  43. FileStream fs = new FileStream("ServerIPAndPort.txt", FileMode.Open);
  44. StreamReader sr = new StreamReader(fs);
  45. string IPAndPort = sr.ReadLine();
  46. ServerIP = IPAndPort.Split(':')[]; //设定IP
  47. port = int.Parse(IPAndPort.Split(':')[]); //设定端口
  48. sr.Close();
  49. fs.Close();
  50. }
  51. catch (Exception ex)
  52. {
  53. MessageBox.Show("配置IP与端口失败,错误原因:" + ex.Message);
  54. Application.Exit();
  55. }
  56. }
  57.  
  58. /// <summary>
  59. /// 打开客户端,即连接服务器
  60. /// </summary>
  61. private void ConnectServer()
  62. {
  63. btn_Login.Enabled = false;
  64. try
  65. {
  66. //此处为方便演示,实际使用时要将Dns.GetHostName()改为服务器域名
  67. //IPAddress ipAd = IPAddress.Parse("182.150.193.7");
  68. client = new TcpClient();
  69. client.Connect(IPAddress.Parse(ServerIP), port);
  70. AddTalkMessage("连接成功\r\n");
  71. }
  72. catch (Exception ex)
  73. {
  74. AddTalkMessage("连接失败,原因:" + ex.Message + "\r\n");
  75. btn_Login.Enabled = true;
  76. return;
  77. }
  78. //获取网络流
  79. NetworkStream networkStream = client.GetStream();
  80. //将网络流作为二进制读写对象
  81. br = new BinaryReader(networkStream);
  82. bw = new BinaryWriter(networkStream);
  83. SendMessage("Login," + txt_UserName.Text);
  84. Thread threadReceive = new Thread(new ThreadStart(ReceiveData));
  85. threadReceive.IsBackground = true;
  86. threadReceive.Start();
  87. }
  88.  
  89. /// <summary>
  90. /// 【登陆】按钮事件
  91. /// </summary>
  92. /// <param name="sender"></param>
  93. /// <param name="e"></param>
  94. private void btn_Login_Click(object sender, EventArgs e)
  95. {
  96. ConnectServer();
  97. }
  98.  
  99. /// <summary>
  100. /// 处理服务器信息
  101. /// </summary>
  102. private void ReceiveData()
  103. {
  104. string receiveString = null;
  105. while (isExit == false)
  106. {
  107. try
  108. {
  109. //从网络流中读出字符串
  110. //此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
  111. receiveString = br.ReadString();
  112. }
  113. catch
  114. {
  115. if (isExit == false)
  116. {
  117. MessageBox.Show("与服务器失去连接");
  118. }
  119. break;
  120. }
  121. string[] splitString = receiveString.Split(',');
  122. string command = splitString[].ToLower();
  123. switch (command)
  124. {
  125. case "login": //格式: login,用户名
  126. AddOnline(splitString[]);
  127. break;
  128. case "logout": //格式: logout,用户名
  129. RemoveUserName(splitString[]);
  130. break;
  131. case "talk": //格式: talk,用户名,对话信息
  132. AddTalkMessage(splitString[] + ":\r\n");
  133. AddTalkMessage(receiveString.Substring(splitString[].Length + splitString[].Length + ) + "\r\n");
  134. break;
  135. default:
  136. AddTalkMessage("错误:" + receiveString + "\r\n");
  137. break;
  138. }
  139. }
  140. Application.Exit();
  141. }
  142.  
  143. /// <summary>
  144. /// 向服务端发送消息
  145. /// </summary>
  146. /// <param name="message"></param>
  147. private void SendMessage(string message)
  148. {
  149. try
  150. {
  151. //将字符串写入网络流,此方法会自动附加字符串长度前缀
  152. bw.Write(message);
  153. bw.Flush();
  154. }
  155. catch
  156. {
  157. AddTalkMessage("发送失败\r\n");
  158. }
  159. }
  160.  
  161. private delegate void AddTalkMessageDelegate(string message);
  162. /// <summary>
  163. /// 在聊天对话框(txt_Message)中追加聊天信息
  164. /// </summary>
  165. /// <param name="message"></param>
  166. private void AddTalkMessage(string message)
  167. {
  168. if (txt_Message.InvokeRequired)
  169. {
  170. AddTalkMessageDelegate d = new AddTalkMessageDelegate(AddTalkMessage);
  171. txt_Message.Invoke(d, new object[] { message });
  172. }
  173. else
  174. {
  175. txt_Message.AppendText(message);
  176. txt_Message.ScrollToCaret();
  177. }
  178. }
  179.  
  180. private delegate void AddOnlineDelegate(string message);
  181. /// <summary>
  182. /// 在在线框(lst_Online)中添加其他客户端信息
  183. /// </summary>
  184. /// <param name="userName"></param>
  185. private void AddOnline(string userName)
  186. {
  187. if (lst_OnlineUser.InvokeRequired)
  188. {
  189. AddOnlineDelegate d = new AddOnlineDelegate(AddOnline);
  190. lst_OnlineUser.Invoke(d, new object[] { userName });
  191. }
  192. else
  193. {
  194. lst_OnlineUser.Items.Add(userName);
  195. lst_OnlineUser.SelectedIndex = lst_OnlineUser.Items.Count - ;
  196. lst_OnlineUser.ClearSelected();
  197. }
  198. }
  199.  
  200. private delegate void RemoveUserNameDelegate(string userName);
  201. /// <summary>
  202. /// 在在线框(lst_Online)中移除不在线的客户端信息
  203. /// </summary>
  204. /// <param name="userName"></param>
  205. private void RemoveUserName(string userName)
  206. {
  207. if (lst_OnlineUser.InvokeRequired)
  208. {
  209. RemoveUserNameDelegate d = new RemoveUserNameDelegate(RemoveUserName);
  210. lst_OnlineUser.Invoke(d, userName);
  211. }
  212. else
  213. {
  214. lst_OnlineUser.Items.Remove(userName);
  215. lst_OnlineUser.SelectedIndex = lst_OnlineUser.Items.Count - ;
  216. lst_OnlineUser.ClearSelected();
  217. }
  218. }
  219.  
  220. /// <summary>
  221. /// 【发送】按钮单击事件
  222. /// </summary>
  223. /// <param name="sender"></param>
  224. /// <param name="e"></param>
  225. private void btn_Send_Click(object sender, EventArgs e)
  226. {
  227. if (txt_SendText.Text == "")
  228. {
  229. MessageBox.Show("发送不能为空!");
  230. return;
  231. }
  232. if (lst_OnlineUser.Text == "所有人" || lst_OnlineUser.Text == "")
  233. {
  234. SendMessage("AllTalk,all," + txt_SendText.Text + "\r\n");
  235. }
  236. else
  237. {
  238. SendMessage("Talk," + lst_OnlineUser.SelectedItem + "," + txt_SendText.Text + "\r\n");
  239. }
  240. txt_SendText.Clear();
  241. }
  242.  
  243. /// <summary>
  244. /// 在发送信息的文本框中按下【Enter】键触发的事件
  245. /// </summary>
  246. /// <param name="sender"></param>
  247. /// <param name="e"></param>
  248. private void txt_SendText_KeyPress(object sender, KeyPressEventArgs e)
  249. {
  250. if (e.KeyChar == (char)Keys.Return)
  251. {
  252. txt_SendText.Text = txt_SendText.Text.Substring(, txt_SendText.Text.Length - );
  253. //触发【发送】按钮的单击事件
  254. btn_Send.PerformClick();
  255. }
  256. }
  257.  
  258. /// <summary>
  259. /// 窗体关闭事件
  260. /// </summary>
  261. /// <param name="sender"></param>
  262. /// <param name="e"></param>
  263. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  264. {
  265. //未与服务器连接前 client 为 null
  266. if (client != null)
  267. {
  268. try
  269. {
  270. SendMessage("Logout," + txt_UserName.Text);
  271. isExit = true;
  272. br.Close();
  273. bw.Close();
  274. client.Close();
  275. }
  276. catch
  277. {
  278. }
  279. }
  280. }
  281.  
  282. }
  283. }

实现效果:

socket学习之聊天室的更多相关文章

  1. 【总结】学习Socket编写的聊天室小程序

    1.前言 在学习Socket之前,先来学习点网络相关的知识吧,自己学习过程中的一些总结,Socket是一门很高深的学问,本文只是Socket一些最基础的东西,大神请自觉绕路. 传输协议 TCP:Tra ...

  2. Socket.io官方聊天室DEMO的学习笔记

    照着Socket.io官方的聊天室代码敲了一遍,遇到了一个奇怪的问题: 每次点击SEND按钮的时候,都会重新刷新页面. 在点击页面的一瞬间,看到了正在加载jquery的提示, 然后以为是jquery用 ...

  3. 使用socket.io搭建聊天室

    最近在学习nodejs,需要找一些项目练练手.找来找去发现了一个聊天室的教程,足够简单,也能从中学到一些东西.下面记录我练习过程中待一些笔记. nodeJS模块 共用到了2个模块,express和so ...

  4. node.js + socket.io实现聊天室一

    前段时间,公司打算在社区做一个聊天室.决定让我来做.本小白第一次做聊天类功能,当时还想着通过ajax请求来实现.经过经理提示,说试试当前流行的node.js 和socket.io来做.于是就上网学习研 ...

  5. 【C++】基于socket的多线程聊天室(控制台版)

    以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...

  6. C#基于Socket的简单聊天室实践

    序:实现一个基于Socket的简易的聊天室,实现的思路如下: 程序的结构:多个客户端+一个服务端,客户端都是向服务端发送消息,然后服务端转发给所有的客户端,这样形成一个简单的聊天室功能. 实现的细节: ...

  7. Socket.io在线聊天室

    从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏 ...

  8. 使用 Socket.IO 开发聊天室

    前言 Socket.IO 是一个用来实现实时双向通信的框架,其本质是基于 WebSocket 技术. 我们首先来聊聊 WebSocket 技术,先设想这么一个场景: · 用户小A,打开了某个网站的充值 ...

  9. Socket实现简易聊天室,Client,Server

    package seday08; import java.io.BufferedWriter;import java.io.OutputStream;import java.io.OutputStre ...

随机推荐

  1. kFreeBSD有活过来的迹象?UbuntuBSD

    那些年追过的FreeBSD分支,有debian系的kFreeBSD,arch系的archBSD现在叫pacBSD,gentoo系的gentooBSD:但基本上在虚拟机环境很难成功安装http://ww ...

  2. 【Linux_Fedora_应用系列】_4_安装chrome浏览器

    在前面一篇文章中,我们讨论了在Linux Fedora 14下安装WMV解码器:[Linux_Fedora_应用系列]_3_如何利用Smplayer播放WMV格式的文件 在文章中介绍的方法同样适合FC ...

  3. 阿里社招B2B

    岗位描述:1. 按USE CASE进行业务需求分析和软件概要设计2. 进行软件详细设计和编码实现,确保性能.质量和安全3. 维护和升级现有软件产品,快速定位并修复现有软件缺陷岗位要求:1. 精通Web ...

  4. Java集合源码分析(七)HashMap<K, V>

    一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了不同步和允许使用 null 之外,HashMap  ...

  5. CentOS 6.5/6.6 安装(install)mysql 5.7 最完整版教程

    Step1: 检测系统是否自带安装mysql # yum list installed | grep mysql Step2: 删除系统自带的mysql及其依赖命令: # yum -y remove ...

  6. 一个完整的类用来生成RSACryptoServiceProvider单例类(.NET)

    internal class CcbRsaCryptProvider { private static RSACryptoServiceProvider _providerForSign; priva ...

  7. jstl标签2

    我们前面讲的是ArrayList集合迭代,Hashmap/Hashset的情况下 举例: <h3>对map和set的迭代</h3> 放入字符串 <% //模拟 Map m ...

  8. JavaScript获取浏览器高度和宽度值

    IE中:  document.body.clientWidth ==> *DY对象宽度 document.body.clientHeight ==> *DY对象高度 document.do ...

  9. SQL增强之Merge

    SQL Server 2008提供了一个增强的SQL命令Merge,用法参看MSDN:http://msdn.microsoft.com/zh-cn/library/bb510625.aspx 功能: ...

  10. sql联合查询

    联合查询效率较高.以下例子来说明联合查询的好处 t1表结构(用户名,密码)    userid int         username   varchar(20)     password      ...