最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位,所以不会SOCKET是不行的。
首先,本文主要是针对那些刚接触SOCKET编程的朋友,如果是高手,就可以不看此文啦,可以去陪陪老婆,比如逛街或看电视...
在开始之前,我们需要预习一些基础知识:
什么是SOCKET套接字?
SOCKET通常有那几种数据格式?
线程的概念?
(以上基本知识我就不讲了,网上这方面资料很多的,大家找资料看下吧)
我要介绍的是一个服务器端+客户端的聊天系统,程序比较简单,我先把程序运行的界面给大家看下:
上面是服务器端运行界面;下面把客户端界面贴给大家看下:
功能比较简单,服务器的端口号可以在“系统菜单”里面的参数配置进行修改的。
看了上面的图,下面我们就给大家把代码贴出来:(因为程序比较简单,所以本人就没有去分层啦)
服务器端代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 9 using System.Net; 10 using System.Net.Sockets; 11 using System.Threading; 12 using System.Xml; 13 14 namespace Server 15 { 16 public partial class ServerMain : Form 17 { 18 public ServerMain() 19 { 20 InitializeComponent(); 21 } 22 23 private void ServerMain_Load( object sender, EventArgs e) 24 { 25 this .CmdStar.Enabled = true ; 26 this .CmdStop.Enabled = false ; 27 } 28 29 private void 配置参数ToolStripMenuItem_Click( object sender, EventArgs e) 30 { 31 Set TSet = new Set(); 32 TSet.ShowDialog(); 33 } 34 35 private void 关于ToolStripMenuItem_Click( object sender, EventArgs e) 36 { 37 About TAbout = new About(); 38 TAbout.Show(); 39 } 40 /// <summary> 41 /// 获得XML文件中的端口号 42 /// </summary> 43 /// <returns></returns> 44 private int GetPort() 45 { 46 try 47 { 48 XmlDocument TDoc = new XmlDocument(); 49 TDoc.Load( " Settings.xml " ); 50 string TPort = TDoc.GetElementsByTagName( " ServerPort " )[ 0 ].InnerXml; 51 return Convert.ToInt32(TPort); 52 53 } 54 catch { return 6600 ; } // 默认是6600 55 } 56 57 // 声明将要用到的类 58 private IPEndPoint ServerInfo; // 存放服务器的IP和端口信息 59 private Socket ServerSocket; // 服务端运行的SOCKET 60 private Thread ServerThread; // 服务端运行的线程 61 private Socket[] ClientSocket; // 为客户端建立的SOCKET连接 62 private int ClientNumb; // 存放客户端数量 63 private byte [] MsgBuffer; // 存放消息数据 64 65 private void CmdStar_Click( object sender, EventArgs e) 66 { 67 ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 68 ServerInfo = new IPEndPoint(IPAddress.Any, this .GetPort()); 69 ServerSocket.Bind(ServerInfo); // 将SOCKET接口和IP端口绑定 70 ServerSocket.Listen( 10 ); // 开始监听,并且挂起数为10 71 72 ClientSocket = new Socket[ 65535 ]; // 为客户端提供连接个数 73 MsgBuffer = new byte [ 65535 ]; // 消息数据大小 74 ClientNumb = 0 ; // 数量从0开始统计 75 76 ServerThread = new Thread(RecieveAccept); // 将接受客户端连接的方法委托给线程 77 ServerThread.Start(); // 线程开始运行 78 79 CheckForIllegalCrossThreadCalls = false ; // 不捕获对错误线程的调用 80 81 this .CmdStar.Enabled = false ; 82 this .CmdStop.Enabled = true ; 83 this .StateMsg.Text = " 服务正在运行 " + " 运行端口: " + this .GetPort().ToString(); 84 this .ClientList.Items.Add( " 服务于 " + DateTime.Now.ToString() + " 开始运行. " ); 85 } 86 87 // 接受客户端连接的方法 88 private void RecieveAccept() 89 { 90 while ( true ) 91 { 92 ClientSocket[ClientNumb] = ServerSocket.Accept(); 93 ClientSocket[ClientNumb].BeginReceive(MsgBuffer, 0 , MsgBuffer.Length, 0 , new AsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]); 94 this .ClientList.Items.Add(ClientSocket[ClientNumb].RemoteEndPoint.ToString() + " 成功连接服务器. " ); 95 ClientNumb ++ ; 96 } 97 } 98 99 // 回发数据给客户端 100 private void RecieveCallBack(IAsyncResult AR) 101 { 102 try 103 { 104 Socket RSocket = (Socket)AR.AsyncState; 105 int REnd = RSocket.EndReceive(AR); 106 for ( int i = 0 ; i < ClientNumb; i ++ ) 107 { 108 if (ClientSocket[i].Connected) 109 { 110 ClientSocket[i].Send(MsgBuffer, 0 , REnd, 0 ); 111 } 112 RSocket.BeginReceive(MsgBuffer, 0 , MsgBuffer.Length, 0 , new AsyncCallback(RecieveCallBack), RSocket); 113 114 } 115 } 116 catch { } 117 118 } 119 120 private void CmdStop_Click( object sender, EventArgs e) 121 { 122 ServerThread.Abort(); // 线程终止 123 ServerSocket.Close(); // 关闭SOCKET 124 125 this .CmdStar.Enabled = true ; 126 this .CmdStop.Enabled = false ; 127 this .StateMsg.Text = " 等待运行 " ; 128 this .ClientList.Items.Add( " 服务于 " + DateTime.Now.ToString() + " 停止运行. " ); 129 } 130 131 132 133 } 134 } 客户端代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 9 using System.Net; 10 using System.Net.Sockets; 11 12 namespace Client 13 { 14 public partial class ClientMain : Form 15 { 16 public ClientMain() 17 { 18 InitializeComponent(); 19 } 20 21 private IPEndPoint ServerInfo; 22 private Socket ClientSocket; 23 private Byte[] MsgBuffer; 24 private Byte[] MsgSend; 25 26 private void ClientMain_Load( object sender, EventArgs e) 27 { 28 this .CmdSend.Enabled = false ; 29 this .CmdExit.Enabled = false ; 30 31 ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 32 MsgBuffer = new Byte[ 65535 ]; 33 MsgSend = new Byte[ 65535 ]; 34 CheckForIllegalCrossThreadCalls = false ; 35 36 Random TRand = new Random(); 37 this .UserName.Text = " 用户 " + TRand.Next( 10000 ).ToString(); 38 } 39 40 private void CmdEnter_Click( object sender, EventArgs e) 41 { 42 ServerInfo = new IPEndPoint(IPAddress.Parse( this .ServerIP.Text), Convert.ToInt32( this .ServerPort.Text)); 43 44 try 45 { 46 ClientSocket.Connect(ServerInfo); 47 48 ClientSocket.Send(Encoding.Unicode.GetBytes( " 用户: " + this .UserName.Text + " 进入系统!\n " )); 49 50 ClientSocket.BeginReceive(MsgBuffer, 0 , MsgBuffer.Length, 0 , new AsyncCallback(ReceiveCallBack), null ); 51 52 this .SysMsg.Text += " 登录服务器成功!\n " ; 53 this .CmdSend.Enabled = true ; 54 this .CmdEnter.Enabled = false ; 55 this .CmdExit.Enabled = true ; 56 } 57 catch 58 { 59 MessageBox.Show( " 登录服务器失败,请确认服务器是否正常工作! " ); 60 } 61 } 62 63 private void ReceiveCallBack(IAsyncResult AR) 64 { 65 try 66 { 67 int REnd = ClientSocket.EndReceive(AR); 68 this .RecieveMsg.AppendText(Encoding.Unicode.GetString(MsgBuffer, 0 , REnd)); 69 ClientSocket.BeginReceive(MsgBuffer, 0 , MsgBuffer.Length, 0 , new AsyncCallback(ReceiveCallBack), null ); 70 71 } 72 catch 73 { 74 MessageBox.Show( " 已经与服务器断开连接! " ); 75 this .Close(); 76 } 77 78 } 79 80 private void CmdSend_Click( object sender, EventArgs e) 81 { 82 MsgSend = Encoding.Unicode.GetBytes( this .UserName.Text + " 说:\n " + this .SendMsg.Text + " \n " ); 83 if (ClientSocket.Connected) 84 { 85 ClientSocket.Send(MsgSend); 86 this .SendMsg.Text = "" ; 87 } 88 else 89 { 90 MessageBox.Show( " 当前与服务器断开连接,无法发送信息! " ); 91 } 92 } 93 94 private void CmdExit_Click( object sender, EventArgs e) 95 { 96 if (ClientSocket.Connected) 97 { 98 ClientSocket.Send(Encoding.Unicode.GetBytes( this .UserName.Text + " 离开了房间!\n " )); 99 ClientSocket.Shutdown(SocketShutdown.Both); 100 ClientSocket.Disconnect( false ); 101 } 102 ClientSocket.Close(); 103 104 this .CmdSend.Enabled = false ; 105 this .CmdEnter.Enabled = true ; 106 this .CmdExit.Enabled = false ; 107 } 108 109 private void RecieveMsg_TextChanged( object sender, EventArgs e) 110 { 111 this .RecieveMsg.ScrollToCaret(); 112 } 113 114 private void SendMsg_KeyDown( object sender, KeyEventArgs e) 115 { 116 if (e.Control && e.KeyValue == 13 ) 117 { 118 e.Handled = true ; 119 this .CmdSend_Click( this , null ); 120 } 121 } 122 123 124 125 126 } 127 } 我只对服务器端的代码做了注释,客户端就没有写注释了,因为代码是差不多的。区别在于客户端不需要监听,也不需要启用线程进行委托。
关于
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);这句代码,我想给初学者解释一下,这里“AddressFamily.InterNetwork”表示的是使用IPV4地址,“SocketType.Stream”表示使用的是流格式(另外还有数据包格式和原始套接字格式),“ProtocolType.Tcp”表示使用TCP协议(另外还有很多其它协议,例如大家常看到的UDP协议)。
另外关于SOCKET类中的
BeginReceive方法,请大家参考MSDN,里面有详细说明。 希望本人给的这个程序可以起到一个抛砖引玉的作用,不明白之处可以加QQ(17020415)或留言。
备注: //2007-12-01 //今天有朋友加我QQ问我有关服务端“Settings.xml”文件的内容部分,我现在把内容贴出来,其实很简单,就是方便服务端修改端口的。 <? xml version="1.0" encoding="utf-8" ?> < Server > < ServerPort > 6600 </ ServerPort > </ Server > 完整的源码我已经放在CSDN上面共享了,地址:
本文转自黄聪博客园博客,原文链接:http://www.cnblogs.com/huangcong/archive/2010/03/27/1698434.html,如需转载请自行联系原作者