界面布局我就不详细说了,直接看后台代码:
界面:
代码:
一些定义:
private Socket serverSocket; //服务器端的socket
private Thread serverThread; //服务器端线程
//保存已连接的客户端socket
private List<Socket> clientSocketList;
//保存已开启的接收数据的客户端线程
private List<Thread> clientThreadList;
private byte[] result = new byte[1024];
Action<String> AsyncUIDelegate;
private string IP = "";
private int Port;
方法:
初始化:
//初始化界面元素
private void initView()
{
//初始化ip下拉框
string[] ipAddress = getLocalAddress();
for (int i = 0; i < ipAddress.Length; i++)
{
cboIp.Items.Add(ipAddress[i]);
}
//设置下拉框初始值
cboIp.SelectedIndex = 1;
//设置端口号
tbPort.Text = "8990";
//初始化按钮状态
btnStart.Enabled = true;
btnStop.Enabled = false;
//初始化端口号和IP
IP = cboIp.SelectedItem.ToString();
Port = Int32.Parse(tbPort.Text.ToString());
//在子线程中更新界面元素
AsyncUIDelegate = delegate(string message)
{
addMonitorMessage(message);
};
addMonitorMessage("服务器初始化成功!");
}
获取本机的IP地址:
//获取本地IP地址
private string[] getLocalAddress()
{
//获取主机名
string hostName = Dns.GetHostName();
//根据主机名查找
IPHostEntry ipHostEntry = Dns.GetHostEntry(hostName);
string[] result = new string[ipHostEntry.AddressList.Length];
int i = 0;
foreach (IPAddress ipAddress in ipHostEntry.AddressList)
{
result[i] = ipAddress.ToString();
i++;
}
return result;
}
开启服务器的监听线程:
//开启服务器服务
private void startServer()
{
//初始化客户端socket管理列表
clientSocketList = new List<Socket>();
//初始化客户端线程管理列表
clientThreadList = new List<Thread>();
IPAddress ipAddress = IPAddress.Parse(IP);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ipAddress, Port)); //绑定IP地址和端口
serverSocket.Listen(10);//设置最多是个连接排队请求
serverThread = new Thread(ListenerClientConnect);
serverThread.Start();
tbMonitor.Invoke(AsyncUIDelegate, "服务器启动成功!");
}
监听客户端的连接:
//监听客户端连接
private void ListenerClientConnect()
{
while (true)
{
Socket clientSocket = serverSocket.Accept();
//向列表中添加客户端socket
clientSocketList.Add(clientSocket);
tbMonitor.Invoke(AsyncUIDelegate, "监听到一个连接");
//向客户端发送信息
//使用操作系统当前的编码方式编码
clientSocket.Send(Encoding.Default.GetBytes("连接成功!"));
Thread receiverMessage = new Thread(receiverData);
//向列表中添加客户端线程
clientThreadList.Add(receiverMessage);
receiverMessage.Start(clientSocket);
}
}
接收客户端发来的信息:
//接收客户端信息
private void receiverData(Object clientSocket)
{
Socket myClientSocket = (Socket)clientSocket;
while (true)
{
try
{
//服务器端接收消息可能会一直阻塞在Receiver()方法
int receiverNum = myClientSocket.Receive(result);
string message = Encoding.ASCII.GetString(result, 0, receiverNum);
//这里需要判断收到的信息是不是为空,如果为空说明客户端主动断开连接,此时可能受到多条空字符串,所以需要break
if ("".Equals(message))
{
tbMonitor.Invoke(AsyncUIDelegate, "客户端断开连接!");
break;
}
else
{
tbMonitor.Invoke(AsyncUIDelegate, "收到的信息:" + message);
}
}
catch (Exception)
{
//myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
}
}
}
停止服务端和向文本框中添加文本:
//停止服务
private void stopServer()
{
//这两行的位置不能颠倒,颠倒程序会卡死在这,具体卡死的原因还不清楚
serverSocket.Close();
serverThread.Abort();
for (int i = 0; i < clientSocketList.Count; i++)
{
clientSocketList[i].Disconnect(true);
}
for (int i = 0; i < clientThreadList.Count; i++)
{
clientThreadList[i].Abort();
}
tbMonitor.Invoke(AsyncUIDelegate, "服务器关闭!");
}
添加文本信息:
private void addMonitorMessage(string message)
{
if ("".Equals(tbMonitor.Text))
{
tbMonitor.Text = message + "\r\n";
}
else
{
tbMonitor.Text += message + "\r\n";
}
}
剩余的其他简单功能:
//开始按钮
private void btnStart_Click(object sender, EventArgs e)
{
addMonitorMessage("正在开启服务器......");
startServer();
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
addMonitorMessage("正在关闭服务器......");
stopServer();
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void cboIp_SelectedIndexChanged(object sender, EventArgs e)
{
IP = cboIp.SelectedItem.ToString();
}
private void tbPort_TextChanged(object sender, EventArgs e)
{
Port = Int32.Parse(tbPort.Text.ToString());
}
最终可以进行测试。有任何问题还请评论告诉我,这只是简单的socket通信,很多地方做的还不完善,会出现某些异常,但是正常情况下通信是没有问题,还有一些未处理的异常请见谅!