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