Socket 编程,一个服务器,多个客户端,互相通信(分享)

西蒙君霸占阿花 2011-09-05 05:35:49
加精
今天我看帖子,有很多关于问Socket的问题.

但是我只能给大家一个很简单的Socket的初级通信.

给大家做一个小的服务器,刚刚好前段时间做了一个小的聊天程序,实现了:

指定客户端发送消息,发送闪屏,支持服务器监听客户端发送消息

具体的代码如下:

首先是服务器.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Net;//Endpoint
using System.Net.Sockets;//包含套接字
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;

namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;//关闭跨线程修改控件检查
}


Socket sokWatch = null;//负责监听 客户端段 连接请求的 套接字(女生宿舍的大妈)
Thread threadWatch = null;//负责 调用套接字, 执行 监听请求的线程

//开启监听 按钮
private void btnStartListen_Click(object sender, EventArgs e)
{
//实例化 套接字 (ip4寻址协议,流式传输,TCP协议)
sokWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建 ip对象
IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
//创建网络节点对象 包含 ip和port
IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
//将 监听套接字 绑定到 对应的IP和端口
sokWatch.Bind(endpoint);
//设置 监听队列 长度为10(同时能够处理 10个连接请求)
sokWatch.Listen(10);
threadWatch = new Thread(StartWatch);
threadWatch.IsBackground = true;
threadWatch.Start();
txtShow.AppendText("启动服务器成功......\r\n");
}

//Dictionary<string, Socket> dictSocket = new Dictionary<string, Socket>();
Dictionary<string, ConnectionClient> dictConn = new Dictionary<string, ConnectionClient>();

bool isWatch = true;

#region 1.被线程调用 监听连接端口
/// <summary>
/// 被线程调用 监听连接端口
/// </summary>
void StartWatch()
{
while (isWatch)
{
//threadWatch.SetApartmentState(ApartmentState.STA);
//监听 客户端 连接请求,但是,Accept会阻断当前线程
Socket sokMsg = sokWatch.Accept();//监听到请求,立即创建负责与该客户端套接字通信的套接字
ConnectionClient connection = new ConnectionClient(sokMsg, ShowMsg, RemoveClientConnection);
//将负责与当前连接请求客户端 通信的套接字所在的连接通信类 对象 装入集合
dictConn.Add(sokMsg.RemoteEndPoint.ToString(), connection);
//将 通信套接字 加入 集合,并以通信套接字的远程IpPort作为键
//dictSocket.Add(sokMsg.RemoteEndPoint.ToString(), sokMsg);
//将 通信套接字的 客户端IP端口保存在下拉框里
cboClient.Items.Add(sokMsg.RemoteEndPoint.ToString());
ShowMsg("接收连接成功......");
//启动一个新线程,负责监听该客户端发来的数据
//Thread threadConnection = new Thread(ReciveMsg);
//threadConnection.IsBackground = true;
//threadConnection.Start(sokMsg);
}
}
#endregion

bool isRec = true;//与客户端通信的套接字 是否 监听消息

#region 发送消息 到指定的客户端 -btnSend_Click
//发送消息 到指定的客户端
private void btnSend_Click(object sender, EventArgs e)
{
//byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(txtInput.Text.Trim());
//从下拉框中 获得 要哪个客户端发送数据
string connectionSokKey = cboClient.Text;
if (!string.IsNullOrEmpty(connectionSokKey))
{
//从字典集合中根据键获得 负责与该客户端通信的套接字,并调用send方法发送数据过去
dictConn[connectionSokKey].Send(txtInput.Text.Trim());
//sokMsg.Send(arrMsg);
}
else
{
MessageBox.Show("请选择要发送的客户端~~");
}
}
#endregion

//发送闪屏!!
private void btnShack_Click(object sender, EventArgs e)
{
string connectionSokKey = cboClient.Text;
if (!string.IsNullOrEmpty(connectionSokKey))
{
dictConn[connectionSokKey].SendShake();
}
else
{
MessageBox.Show("请选择要发送的客户端~~");
}
}
//群闪
private void btnShackAll_Click(object sender, EventArgs e)
{
foreach (ConnectionClient conn in dictConn.Values)
{
conn.SendShake();
}
}

#region 2 移除与指定客户端的连接 +void RemoveClientConnection(string key)
/// <summary>
/// 移除与指定客户端的连接
/// </summary>
/// <param name="key">指定客户端的IP和端口</param>
public void RemoveClientConnection(string key)
{
if (dictConn.ContainsKey(key))
{
dictConn.Remove(key);
cboClient.Items.Remove(key);
}
}
#endregion

//选择要发送的文件
private void btnChooseFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtFilePath.Text = ofd.FileName;
}
}

//发送文件
private void btnSendFile_Click(object sender, EventArgs e)
{
//拿到下拉框中选中的客户端IPPORT
string key = cboClient.Text;
if (!string.IsNullOrEmpty(key))
{
dictConn[key].SendFile(txtFilePath.Text.Trim());
}
}

#region 向文本框显示消息 -void ShowMsg(string msgStr)
/// <summary>
/// 向文本框显示消息
/// </summary>
/// <param name="msgStr">消息</param>
public void ShowMsg(string msgStr)
{
txtShow.AppendText(msgStr + "\r\n");
}
#endregion

private void btnSendMsgAll_Click(object sender, EventArgs e)
{
foreach (ConnectionClient conn in dictConn.Values)
{
conn.Send(txtInput.Text.Trim());
}
}


}
}



至于控件的名字,这里不能贴图,只能给大家去猜了,因为命名还是很规范的.

...全文
21645 229 打赏 收藏 转发到动态 举报
写回复
用AI写文章
229 条回复
切换为时间正序
请发表友善的回复…
发表回复
黑藻 2021-07-01
  • 打赏
  • 举报
回复

ConnectionClient 未能找到类型或引用????

「已注销」 2014-04-20
  • 打赏
  • 举报
回复
正在学习socket,mark
兴风作浪的梦 2013-12-02
  • 打赏
  • 举报
回复
mark 一下以后 有用 嘿嘿
asdfg07 2013-11-26
  • 打赏
  • 举报
回复
下载不了。。。谢谢,能否发一份给我 qwerty-07@163.com 我遇到一个问题: 多个客户端或客户端多次与服务器端连接时,只有一次能添加到字典中,其余都无法添加到服务器端的字典中,应该怎样解决?
衣布遮体 2013-10-17
  • 打赏
  • 举报
回复
感谢楼主分享
Blizzard_X 2013-10-13
  • 打赏
  • 举报
回复
每次连接一个客户端,都要创建一个线程吗?那岂不是很快就崩溃了?
u010928861 2013-06-06
  • 打赏
  • 举报
回复
写的不错啊 感谢楼主
u010928861 2013-06-06
  • 打赏
  • 举报
回复
mark 好贴
hoho0326077 2013-03-07
  • 打赏
  • 举报
回复
mark+nice
喀纳斯 2013-02-25
  • 打赏
  • 举报
回复
收藏了,留着学习一下……
qqzhoushui 2013-02-20
  • 打赏
  • 举报
回复
楼主,还在吗?N年前东西现在来请教....擦.. 我想问的是,现在一个服务端,可以多个客户端,客户端怎么跟客户端通信??
huismessager 2013-02-14
  • 打赏
  • 举报
回复
很好,学习一下
小草的梦想 2013-01-24
  • 打赏
  • 举报
回复
学习学习,谢谢。
alexcjq 2012-12-28
  • 打赏
  • 举报
回复
谢谢楼主分享
nextwhy 2012-12-18
  • 打赏
  • 举报
回复
你好 这个能 实现外网 通讯吗?
wangyd324 2012-12-18
  • 打赏
  • 举报
回复
mark
  • 打赏
  • 举报
回复
wangyd324 2012-12-03
  • 打赏
  • 举报
回复
楼主威武~~
luohuayouy 2012-12-03
  • 打赏
  • 举报
回复
楼主能不能发一份实现的例子到我的邮箱啊350128310@qq.com
刘_半仙 2012-12-03
  • 打赏
  • 举报
回复
收藏了
加载更多回复(209)
环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧