111,086
社区成员




服务端
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
//创建一个负责监听的socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP地址和端口号对象
IPAddress ip = IPAddress.Any; //IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(txtPort.Text));
//让负责监听的socket绑定IP地址和端口号
socketWatch.Bind(point);
ShowMsg("监听成功");
//设置监听队列
socketWatch.Listen(10);
//开启新线程
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
Socket socktSend;
/// <summary>
/// 等待客户端的连接 并且创建与之同信用的socket
/// </summary>
void Listen(object o)
{
Socket socketWatch = o as Socket;
//负责监听的socket 来接受客户端的连接 创建跟客户端通信的socket
while (true)
{
try
{
socktSend = socketWatch.Accept();
//将远程连接的客户端的IP地址和socket存入集合中
dicSocket.Add(socktSend.RemoteEndPoint.ToString(), socktSend);
//将远程连接的客户端的额IP地址和端口号存入下拉框中
cboUsers.Items.Add(socktSend.RemoteEndPoint.ToString());
//连接成功
ShowMsg(socktSend.RemoteEndPoint.ToString() + "连接成功");
//开启一个新线程不停接收来自客户端的消息
Thread th = new Thread(Recive);
th.IsBackground=true;
th.Start(socktSend);
}
catch
{ }
}
}
//将远程连接的客户端的IP地址和socket存入集合中
Dictionary<string,Socket> dicSocket = new Dictionary<string,Socket>();
/// <summary>
///服务器端不停接收客户端发送过来的消息
/// </summary>
/// <param name="o"></param>
void Recive(object o)
{
Socket socketSend = o as Socket;
while(true)
{
try
{
//客户端连接成功后 服务器应该接收客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 3];
int r = socketSend.Receive(buffer);
//发送的文字消息
//if (buffer[0] == 0)
//{
//int代表实际接收到的字节数
if (r == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);//将buffer的东西转换成能看得懂的东西
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
//}
//else if(buffer[0] == 1)
//{
//}
//else if (buffer[0] ==2)
//{
//}
}
catch
{ }
}
}
void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
//List<byte> list = new List<byte>();
//list.Add(0);
//list.AddRange(buffer);
//将泛型集合转换为数组
//byte[] newBuffer = list.ToArray();
//获得用户在下拉框中选中的地址
string ip = cboUsers.SelectedItem.ToString();
dicSocket[ip].Send(buffer);
//socktSend.Send(buffer);
}
}
}
客户端
namespace 客户端连接
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket socketSend;
private void button1_Click(object sender, EventArgs e)
{
//创建负责通信的socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(textBox1.Text);
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(textBox2.Text));//ip地址端口号
//获得要连接远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连接成功");
//开启新的线程 不停的接收服务端发来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start();
}
/// <summary>
/// 不停的接收从服务端传过来的消息
/// </summary>
void Recive()
{
while(true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
int r = socketSend.Receive(buffer);
if (r == 0)
{
break;
}
string s = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint + ":" + s);
}
catch { }
}
}
void ShowMsg(string str)
{
textBox4.AppendText(str + "\r\n");
}
private void button2_Click(object sender, EventArgs e)
{
string str =txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}
}
学习编程要将编程设计理念学到手,包括数据结构、算法、操作系统、各类业务框架、软件工程技术学到手。要始终去寻找真正“上路”的软件套路去设计,要仅仅关心有深度的和能出产品的套路。我们经常招聘时一看有些人展示“作品”,就知道有些人只学了5%不到的皮毛,交了5万块钱学费却学的不值500块,只是糊弄你一点儿界面,那就白费了。
另外要说明一下,代码
Control.CheckForIllegalCrossThreadCalls = false
这个功能本身就是不靠谱的,这个功能是让 winform 消息泵可以胡乱地——冲突地——更新内存状态数据,这个是临时实验学习个别的1、2条语句时可以用,正经程序肯定不能这样。
异步并发的程序,当然必须保证控件刷新也不会冲突,同时又是异步的——刷新一次控件的缓慢过程中不会阻塞与控件无关的算法代码执行上万次。所以算法程序可以在独立的线程中运行,它访问控件应该使用异步回调方式设计流程,并且等待回调的过程不应该干扰计算的主循环过程。
现代的 .net 编程大量使用了 Task(async/await)技术语法来编写。
具体来说,一个TCP网关程序应该是一个 Application 的“底层”的独立的线程,你的应用启动了这样一个网关线程之后,这个独立底层代码自己去收发消息,一旦有消息到来就抛出异步事件通知,上层发送接口一旦被调用就将任务方法推入线程池(ThreadPool.QueueUserWorkItem(() => { .....}) 或者 await MySendMessge(....) 这类代码)。而如果业务层要捕获收到的结构化的消息,进行进一步业务解析执行,应该向网关先注册一个事件监听,这样网关就能异步推送事件调用功能给业务层,这也丝毫不会影响网关收发数据和解析信令的效率,业务层的 bug 也不会干扰通讯网关运行。
没时间细看你的代码。给你一些开发建议:
通讯程序必须在双向、两端都把接收和发送的报文摘要和时间(起码到毫秒)打印出来,然后你再去观察问题成因。比如说一段频繁大量发送冗余信息,或者错误报文,或者一端的解析程序实际上报一大堆信令解析错误,等等,这些都要有日志,有时候一秒钟能产生和打印几百条上千条。这样才能搞通讯开发。
winform复杂,服务端更复杂,要不要请个teacher?
不知道有多少前人掉在TCP Socket
send(人多)send(病少)send(财富)
recv(人多病)recv(少财富)
陷阱里面啊!
▼ http://bbs.csdn.net/topics/380167545
socketWatch.Listen(10);
这句话的意思,理解一下
话说,真想做这个就请不要在某个园子抄代码,某个园子的代码质量可是不能保证的。正确的途径是在nuget,git上去找星标项目。
有人人很烦我提园子,但是不提不行哦。来这里提问题的,90%都是被园子代码给带坑里,然后过来寻求帮助的。
所以我们的意思就这样了“如果你一开始就不抄他们那些到处是坑的玩意,自然就不会踩坑,也不会让我们来帮你解决坑”