黑马程序员技术交流社区
标题:
关于UDP同步的winform小程序,陷进问题里了
[打印本页]
作者:
qiumanlover
时间:
2013-5-27 21:35
标题:
关于UDP同步的winform小程序,陷进问题里了
本帖最后由 qiumanlover 于 2013-5-29 13:48 编辑
服务端和客户端是一样的程序,即只有一个程序,开两个,绑定不同地址,然后实现通讯。
发送消息是通过监听TextBox的KeyDown事件实现的,接收消息是放在线程里的
现在的问题是:两边的程序只能接受一次对方的消息,此后就收不到了
如果将接受消息的方法放在按键事件里,则会卡住输入框,直到收到对面的消息
源码如下:
using System;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace UDP_SYN
{
public partial class UDPClient : Form
{
private IPEndPoint localIpe = null; //本地节点
private Socket localSock = null; //绑定本地节点的套接字
private static IPEndPoint remoteIpe = null; //远程结点
private EndPoint Remote = null; //用于接收消息的抽象对象结点
private byte[] sendbuff = new byte[1024]; //发送缓冲区
private byte[] recvbuff = new byte[1024]; //接收缓冲区
private int msgLen; //接收的数据的字节长度
public UDPClient()
{
CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false; //关闭文本框的跨线程检查
}
private void Form1_Load(object sender, EventArgs e)
{
button1.Enabled = true;
txtSend.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
localIpe = new IPEndPoint(IPAddress.Parse(txtLocalIP.Text.ToString().Trim()),
Convert.ToInt32(txtLocalPort.Text.ToString().Trim()));
localSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
remoteIpe = new IPEndPoint(IPAddress.Parse(txtRemoteIP.Text.ToString().Trim()),
Convert.ToInt32(txtRemotePort.Text.ToString().Trim()));
localSock.Bind(localIpe);
Thread startThrd = new Thread(new ThreadStart(RecvThrd));
startThrd.IsBackground = true;
startThrd.Start();
//处理按键之后的页面布局,阻止修改配置
txtSend.Enabled = true;
button1.Enabled = false;
txtLocalIP.Enabled = false;
txtLocalPort.Enabled = false;
txtRemoteIP.Enabled = false;
txtRemotePort.Enabled = false;
txtSend.Focus();
}
//按下回车键发送消息,并显示在自己的接收消息窗口
private void txtSend_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
try
{
sendbuff = Encoding.ASCII.GetBytes(txtSend.Text.ToString());
localSock.SendTo(sendbuff, remoteIpe);
txtRecv.AppendText(localSock.LocalEndPoint.ToString() + " " +
DateTime.Now.ToString() + " " + remoteIpe.ToString()
+ "\r\n\t" + txtSend.Text.ToString() + "\r\n");
SendKeys.Send("{BackSpace}");
txtSend.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
//接收消息的方法,放入线程,防止阻塞当前窗口
private void RecvThrd()
{
Remote = (EndPoint)(remoteIpe);
msgLen = localSock.ReceiveFrom(recvbuff, ref Remote);
Remote = (EndPoint)(remoteIpe);
ShowMsg(Encoding.ASCII.GetString(recvbuff, 0, msgLen));
}
public void ShowMsg(string str)
{
txtRecv.AppendText(Remote.ToString() + " " + DateTime.Now.ToString()
+ " " + Remote.ToString() + "\r\n\t" + str + "\r\n");
}
}
}
复制代码
作者:
Xi_SHENG:
时间:
2013-5-27 23:16
先沙发......
作者:
a724228803
时间:
2013-5-29 21:58
要想持续监听接受消息,就必须调用新的线程来专门负责监听发来的消息,可以参考我都代码解析:
服务端namespace 客户端连接
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false; //关闭跨线程调用
}
Thread watchthread=null;//j将监听套接字定义在类中,方便调用
Dictionary<string,Socket> dict=new Dictionary<string,Socket>();
// 定义字典链表,来存储申请连接用户的IP和端口即套接字信息
Dictionary<string, Socket> dictrec = new Dictionary<string, Socket>();
//定义字典列表,用来存连接客户端的套接字
Socket socketWatch=null;
private void protbtn_Click(object sender, EventArgs e)
{ //创建服务端的监听套接字,参数(使用 的IP寻址协议,使用流式连接,使用TCP协议传输数据)
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 获取文本框的IP地址对象。
IPAddress address = IPAddress.Parse(iptxt.Text.Trim());
//创建含有IP和port的网络节点对象
IPEndPoint endpoint=new IPEndPoint(address,int.Parse(prottxt.Text.Trim()));
//将负责监听的套接字绑定到唯一的IP端口上
socketWatch.Bind(endpoint);
//设置监听队列的长度
socketWatch.Listen(10);
//
watchthread = new Thread(WTC);
//给线程委托
watchthread.IsBackground = true;
//绑定后台线程
watchthread.Start();
//线程开始
}
private void showMsg(string p)
{
txtb1.AppendText(p+"\r\n");
}
void WTC()
{
while (true)//持续监听
{
Socket socketconnecttion = socketWatch.Accept();//一旦监听到了请求,返回新的通讯的docket。
//将新生成的IP和端口信息和socket加入到字典的键和值
dict.Add(socketconnecttion.RemoteEndPoint.ToString(),socketconnecttion);
//将连接的客户端IP加入到控件的列表
onlinelist.Items.Add(socketconnecttion.RemoteEndPoint.ToString());
//将远程客户端计算机的IP和端口 添加到onlinelist列表
Thread recThread = new Thread(Rec);
//与客户端建立连接后,持续监听客户端是否发送信息,有新的线程来监听
recThread.IsBackground = true;//后台
recThread.Start(socketconnecttion);//传参,当前生成的socket
showMsg("客户端连接成功!"+socketconnecttion.RemoteEndPoint.ToString()+"\r\n");
}
}
void Rec(object socketconnet)
{
while (true)//持续接收客户端消息
{
Socket socketconnettion = socketconnet as Socket;//强制转换成socket
byte[] arrmsg = new byte[1024 * 1024 * 2];
//定义2M字节序列 ,来接受 用户消息
int length;
length = socketconnettion.Receive(arrmsg);
//接受客户端的消息
if (arrmsg[0] == 0)//判断客户端发来的是文字还是文件 0是文字 1是文件
{
string str = System.Text.Encoding.UTF8.GetString(arrmsg, 1, length);
//将字节序列转换成字符串
showMsg("客户端--->" + str);
}
else
if (arrmsg[0] == 1)//当接受是文件时
{
SaveFileDialog sfd = new SaveFileDialog();
//实例化保存文件对话框
if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
//当保存成功, 将文件名赋给变量filesavepath
{
string filesavepath = sfd.FileName;
using (FileStream fs = new FileStream(filesavepath, FileMode.Create))//(文件路径,文件模式)
//文件流很占内存,所以用using及时释放
{
fs.Write(arrmsg, 1, length - 1);
showMsg("文件保存成功!"+filesavepath);
}
}
}
}
}
private void btnsend_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(onlinelist.Text))
{
MessageBox.Show("请先选择一个好友");
return;
}
else
{
string str = txtserver.Text.Trim();
//将要发送的字符串转换成utf8对应的字节数组
byte[] arrmsg = System.Text.Encoding.UTF8.GetBytes(str);
string strclientKey = onlinelist.Text;
//通过 键 查询 值(即客户的套接字) 来调用值的send()来发送信息
dict[strclientKey].Send(arrmsg);
//socketconnecttion.Send(arrmsg);
showMsg("服务端:--->" + str + "\r\n");
}
}
private void button1_Click(object sender, EventArgs e)
{ //服务端发送信息
string str = txtserver.Text.Trim();
byte[] byarr = new byte[1024 * 1024 * 2];
byarr = System.Text.Encoding.UTF8.GetBytes(str);
//将字符串转换成字节序列
foreach (Socket s in dict.Values)
{ //遍历群发
s.Send(byarr);
}
showMsg("群发完毕");
}
}
}
————————————————————————————————
客户端:
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
Socket socketclient = null;
Thread recThread = null;
private void protbtn_Click(object sender, EventArgs e)
{
IPAddress address = IPAddress.Parse(iptxt.Text.Trim());
//从文本框获取IP
IPEndPoint endpoint=new IPEndPoint( address,int.Parse(prottxt.Text.Trim()));
//从文本框获取端口或IP
socketclient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//连接服务器
socketclient.Connect(endpoint);
//调用线程
recThread = new Thread(RecMsg);
recThread.IsBackground = true;
recThread.Start();
}
void RecMsg()
{
while (true)
{
//定义一个接受用的缓存区(2M字节)
byte[] arrmsgrec = new byte[1024 * 1024 * 2];
//将接受到的消息数据传入arrmsgrec数组,并返回真正接受数据的长度
int length=socketclient.Receive(arrmsgrec);
//将字节序列转化为字符串然(要转换的字节序列,开始位置,转换长度)
string strMsgRec = System.Text.Encoding.UTF8.GetString(arrmsgrec, 0, length);
ShowMsg("服务端-->"+strMsgRec);
}
}
void ShowMsg(string str)
{
//想文本框追加文本
txtb1.AppendText( str + "\r\n");
}
private void btnsend_Click(object sender, EventArgs e)
{//客户端向服务端发送信息。
string str = txtclient.Text.Trim();
byte[] byArr = new byte[1024 * 1024 * 2];
byArr = System.Text.Encoding.UTF8.GetBytes(str);
byte[] byarrsend = new byte[byArr.Length + 1];
byarrsend[0] = 0;//发送文字,字节序列首位赋0;
Buffer.BlockCopy(byArr,0,byarrsend,1,byArr.Length);
socketclient.Send(byarrsend);//发送字符序列
ShowMsg("客户端--->"+str);
}
private void filechoosebtn_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();//打开文件选择对话框
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)//判断是否选择文件
{
filepathtxt.Text = ofd.FileName;//在文本框显示文件路径
}
}
private void filesendbtn_Click(object sender, EventArgs e)
{ //发送文件
using (FileStream fs = new FileStream(filepathtxt.Text, FileMode.Open))
{
byte[] arrfile = new byte[1024 * 1024 * 2];
int length = fs.Read(arrfile, 0, arrfile.Length);
byte[] arrsend=new byte[length+1];
arrsend[0] = 1;//第一个为标识为
Buffer.BlockCopy(arrfile,0,arrsend,1,length);
socketclient.Send(arrsend);
}
}
}
}
作者:
袁梦希
时间:
2013-5-30 20:19
大家加油 以后有事情 或者没加分 给我留言或者看我的个性签名
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2