帮忙写一个C#例子:两个进程间通信的问题.
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了帮忙写一个C#例子:两个进程间通信的问题.相关的知识,希望对你有一定的参考价值。
帮忙写一个C#例子,两个进程.利用ip地址和端口来通信.我要看看在两个程序间是如何利用端口来通信的.要有简要注解.如果有多种方法最好全写上.谢谢.
写两个程序,A向B发送信息,B收到后返回给A一个结果.
发送什么都无所谓.我只是想看看两个程序间通信的代码.
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.IO;
namespace ChatClient
public partial class FormClient : Form
private bool isExit = false;
private delegate void SetListBoxCallback(string str);
private SetListBoxCallback setListBoxCallback;
private TcpClient client;
private NetworkStream networkStream;
private BinaryReader br;
private BinaryWriter bw;
public FormClient()
InitializeComponent();
listBoxStatus.HorizontalScrollbar = true;
setListBoxCallback = new SetListBoxCallback(SetListBox);
private void buttonConnect_Click(object sender, EventArgs e)
try
//实际使用时要将Dns.GetHostName()改为服务器域名
client = new TcpClient(Dns.GetHostName(), 51888);
SetListBox(string.Format("本机EndPoint:0", client.Client.LocalEndPoint));
SetListBox("与服务器建立连接成功");
catch
SetListBox("与服务器连接失败");
return;
buttonConnect.Enabled = false;
//获取网络流
networkStream = client.GetStream();
//将网络流作为二进制读写对象,使用UTF8编码
br = new BinaryReader(networkStream);
bw = new BinaryWriter(networkStream);
SendString("Login");
Thread threadReceive = new Thread(new ThreadStart(ReceiveData));
threadReceive.Start();
private void ReceiveData()
while (isExit == false)
string receiveString = null;
try
//从网络流中读出字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString = br.ReadString();
catch
//底层套接字不存在时会出现异常
SetListBox("接收数据失败");
if (receiveString == null)
if (isExit == false)
MessageBox.Show("与服务器失去联系!");
break;
SetListBox("收到:" + receiveString);
Application.Exit();
private string ReadString(int dataLength)
string receiveString;
try
//从网络流中读出字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString = br.ReadString();
return receiveString;
catch
//底层套接字不存在时会出现异常
SetListBox("接收数据失败");
return null;
private void SendString(string str)
try
//将字符串写入网络流,此方法会自动附加字符串长度前缀
bw.Write(str);
bw.Flush();
SetListBox(string.Format("发送:0", str));
catch
SetListBox("发送失败!");
private void SetListBox(string str)
if (listBoxStatus.InvokeRequired == true)
this.Invoke(setListBoxCallback, str);
else
listBoxStatus.Items.Add(str);
listBoxStatus.SelectedIndex = listBoxStatus.Items.Count - 1;
listBoxStatus.ClearSelected();
private void buttonSend_Click(object sender, EventArgs e)
SendString("Talk," + textBoxSend.Text);
textBoxSend.Clear();
private void FormClient_FormClosing(object sender, FormClosingEventArgs e)
//未与服务器连接前client为null
if (client != null)
SendString("Logout");
isExit = true;
br.Close();
bw.Close();
client.Close();
private void textBoxSend_KeyPress(object sender, KeyPressEventArgs e)
if (e.KeyChar == (char)Keys.Return)
buttonSend_Click(null, null);
//Server:
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.IO;
namespace ChatServer
public partial class FormServer : Form
//连接的用户
System.Collections.Generic.List<User> userList = new List<User>();
TcpListener listener;
private delegate void SetListBoxCallback(string str);
private SetListBoxCallback setListBoxCallback;
private delegate void SetComboBoxCallback(User user);
private SetComboBoxCallback setComboBoxCallback;
//使用的本机IP地址
IPAddress localAddress;
//监听端口
private int port = 51888;
private TcpListener myListener;
public FormServer()
InitializeComponent();
listBoxStatus.HorizontalScrollbar = true;
setListBoxCallback = new SetListBoxCallback(SetListBox);
setComboBoxCallback = new SetComboBoxCallback(AddComboBoxitem);
IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());
localAddress = addrIP[0];
buttonStop.Enabled = false;
//【开始监听】按钮的Click事件
private void buttonStart_Click(object sender, EventArgs e)
myListener = new TcpListener(localAddress, port);
myListener.Start();
SetListBox(string.Format("开始在0:1监听客户连接", localAddress, port));
//创建一个线程监听客户端连接请求
ThreadStart ts = new ThreadStart(ListenClientConnect);
Thread myThread = new Thread(ts);
myThread.Start();
buttonStart.Enabled = false;
buttonStop.Enabled = true;
//接收客户端连接
private void ListenClientConnect()
while (true)
TcpClient newClient = null;
try
//等待用户进入
newClient = myListener.AcceptTcpClient();
catch
//当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常
//因此可以利用此异常退出循环
break;
//每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
ParameterizedThreadStart pts = new ParameterizedThreadStart(ReceiveData);
Thread threadReceive = new Thread(pts);
User user = new User(newClient);
threadReceive.Start(user);
userList.Add(user);
AddComboBoxitem(user);
SetListBox(string.Format("[0]进入", newClient.Client.RemoteEndPoint));
SetListBox(string.Format("当前连接用户数:0", userList.Count));
//接收、处理客户端信息,每客户1个线程,参数用于区分是哪个客户
private void ReceiveData(object obj)
User user = (User)obj;
TcpClient client = user.client;
//是否正常退出接收线程
bool normalExit = false;
//用于控制是否退出循环
bool exitWhile = false;
while (exitWhile == false)
string receiveString = null;
try
//从网络流中读出字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString = user.br.ReadString();
catch
//底层套接字不存在时会出现异常
SetListBox("接收数据失败");
if (receiveString == null)
if (normalExit == false)
//如果停止了监听,Connected为false
if (client.Connected == true)
SetListBox(string.Format(
"与[0]失去联系,已终止接收该用户信息", client.Client.RemoteEndPoint));
break;
SetListBox(string.Format("来自[0]:1", user.client.Client.RemoteEndPoint, receiveString));
string[] splitString = receiveString.Split(',');
string sendString = "";
switch (splitString[0])
case "Login":
//格式:Login
sendString = "Hello,我是服务器,你好!";
SendToClient(user, sendString);
break;
case "Logout":
//格式:Logout
SetListBox(string.Format("[0]退出", user.client.Client.RemoteEndPoint));
normalExit = true;
exitWhile = true;
break;
case "Talk":
//格式:Talk,对话内容
SetListBox(string.Format("[0]说:1",client.Client.RemoteEndPoint,
receiveString.Substring(splitString[0].Length + 1)));
break;
default:
SetListBox("什么意思啊:" + receiveString);
break;
userList.Remove(user);
client.Close();
SetListBox(string.Format("当前连接用户数:0", userList.Count));
private void SendToClient(User user, string str)
try
//将字符串写入网络流,此方法会自动附加字符串长度前缀
user.bw.Write(str);
user.bw.Flush();
SetListBox(string.Format("向[0]发送:1", user.client.Client.RemoteEndPoint, str));
catch
SetListBox(string.Format("向[0]发送信息失败", user.client.Client.RemoteEndPoint));
private void AddComboBoxitem(User user)
if (comboBoxReceiver.InvokeRequired == true)
this.Invoke(setComboBoxCallback, user);
else
comboBoxReceiver.Items.Add(user.client.Client.RemoteEndPoint);
private void SetListBox(string str)
if (listBoxStatus.InvokeRequired == true)
this.Invoke(setListBoxCallback, str);
else
listBoxStatus.Items.Add(str);
listBoxStatus.SelectedIndex = listBoxStatus.Items.Count - 1;
listBoxStatus.ClearSelected();
//【停止监听】按钮的Click事件
private void buttonStop_Click(object sender, EventArgs e)
SetListBox(string.Format("目前连接用户数:0", userList.Count));
SetListBox("开始停止服务,并依次使用户退出!");
for (int i = 0; i < userList.Count; i++)
comboBoxReceiver.Items.Remove(userList[i].client.Client.RemoteEndPoint);
userList[i].br.Close();
userList[i].bw.Close();
userList[i].client.Close();
//通过停止监听让myListener.AcceptTcpClient()产生异常退出监听线程
myListener.Stop();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
//【发送】按钮的Click事件
private void buttonSend_Click(object sender, EventArgs e)
int index = comboBoxReceiver.SelectedIndex;
if (index == -1)
MessageBox.Show("请先选择接收方,然后再单击〔发送〕");
else
User user = (User)userList[index];
SendToClient(user, textBoxSend.Text);
textBoxSend.Clear();
private void FormServer_FormClosing(object sender, FormClosingEventArgs e)
//未单击开始监听就直接退出时,myListener为null
if (myListener != null)
buttonStop_Click(null, null);
private void textBoxSend_KeyPress(object sender, KeyPressEventArgs e)
if (e.KeyChar == (char)Keys.Return)
buttonSend_Click(null, null);
参考技术A 看不懂
C# 进程间通信之二传递复杂数据类型(转)
从C#下使用WM_COPYDATA传输数据说到Marshal的应用
笔者曾在一个项目的实施过程中,需要使用WM_COPYDATA在本地机器的两个进程间传输数据。在C++中实现非常简单,但在C#中实现时却出现了麻烦。由于没有指针,使用COPYDATASTRUCT结构传递数据时,无法正确传递lpData。从网上搜寻文档,找到一个例子,是将COPYDATASTRUCT结构的lpData声明为string。这样虽然能传递字符串,但不能传递随意的二进制数据。
偶然地,我查阅MSDN帮助时,发现了Marshal类。该类概述描述道:提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。这时,我豁然开朗,觉得找到了一个托管代码与非托管代码交互的桥梁。
于是我声明COPYDATASTRUCT如下:
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
在发送数据时,我使用Marshal类分配一块全局内存,并将数据拷入这块内存,然后发送消息:
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)flag;
cds.cbData = data.Length;
cds.lpData = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data,0,cds.lpData,data.Length);
SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);
在接收数据时,我使用Marshal类将数据从这块全局内存拷出,然后处理消息:
COPYDATASTRUCT cds = new COPYDATASTRUCT();
Type mytype = cds.GetType();
cds = (COPYDATASTRUCT)m.GetLParam(mytype);
uint flag = (uint)(cds.dwData);
byte[] bt = new byte[cds.cbData];
Marshal.Copy(cds.lpData,bt,0,bt.Length);
详细源码如下:
/// <summary>
/// Windows 的COPYDATA消息封装类。
/// </summary>
public class Messager : System.Windows.Forms.Form
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
//消息标识
private const int WM_COPYDATA = 0x004A;
//消息数据类型(typeFlag以上二进制,typeFlag以下字符)
private const uint typeFlag = 0x8000;
/// <summary>
/// 重载CopyDataStruct
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
//
[DllImport("User32.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
ref COPYDATASTRUCT lParam // second message parameter
);
//
[DllImport("User32.dll",EntryPoint="FindWindow")]
private static extern int FindWindow(string lpClassName,string lpWindowName);
//接收到数据委托与事件定义
public delegate void ReceiveStringEvent(object sender,uint flag,string str);
public delegate void ReceiveBytesEvent(object sender,uint flag,byte[] bt);
public event ReceiveStringEvent OnReceiveString;
public event ReceiveBytesEvent OnReceiveBytes;
//发送数据委托与事件定义
public delegate void SendStringEvent(object sender,uint flag,string str);
public delegate void SendBytesEvent(object sender,uint flag,byte[] bt);
public event SendStringEvent OnSendString;
public event SendBytesEvent OnSendBytes;
//
public Messager()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
//
// Messager
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(200, 14);
this.Name = "Messager";
this.ShowInTaskbar = false;
this.Text = "Demo_Emluator";
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
}
#endregion
/// <summary>
///重载窗口消息处理函数
/// </summary>
/// <param name="m"></param>
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch(m.Msg)
{
//接收CopyData消息,读取发送过来的数据
case WM_COPYDATA:
COPYDATASTRUCT cds = new COPYDATASTRUCT();
Type mytype = cds.GetType();
cds = (COPYDATASTRUCT)m.GetLParam(mytype);
uint flag = (uint)(cds.dwData);
byte[] bt = new byte[cds.cbData];
Marshal.Copy(cds.lpData,bt,0,bt.Length);
if(flag <= typeFlag)
{
if(OnReceiveString != null)
{
OnReceiveString(this,flag,System.Text.Encoding.Default.GetString(bt));
}
}
else
{
if(OnReceiveBytes != null)
{
OnReceiveBytes(this,flag,bt);
}
}
break;
default:
base.DefWndProc(ref m);
break;
}
}
/// <summary>
/// 发送字符串格式数据
/// </summary>
/// <param name="destWindow">目标窗口标题</param>
/// <param name="flag">数据标志</param>
/// <param name="str">数据</param>
/// <returns></returns>
public bool SendString(string destWindow,uint flag,string str)
{
if(flag > typeFlag)
{
MessageBox.Show("要发送的数据不是字符格式");
return false;
}
int WINDOW_HANDLER = FindWindow(null,@destWindow);
if(WINDOW_HANDLER == 0) return false;
try
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(str);
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)flag;
cds.cbData = sarr.Length;
cds.lpData = Marshal.AllocHGlobal(sarr.Length);
Marshal.Copy(sarr,0,cds.lpData,sarr.Length);
SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);
if(OnSendString != null)
{
OnSendString(this,flag,str);
}
return true;
}
catch(Exception e)
{
MessageBox.Show(e.Message);
return false;
}
}
/// <summary>
/// 发送二进制格式数据
/// </summary>
/// <param name="destWindow">目标窗口</param>
/// <param name="flag">数据标志</param>
/// <param name="data">数据</param>
/// <returns></returns>
public bool SendBytes(string destWindow,uint flag,byte[] data)
{
if(flag <= typeFlag)
{
MessageBox.Show("要发送的数据不是二进制格式");
return false;
}
int WINDOW_HANDLER = FindWindow(null,@destWindow);
if(WINDOW_HANDLER == 0) return false;
try
{
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)flag;
cds.cbData = data.Length;
cds.lpData = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data,0,cds.lpData,data.Length);
SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);
if(OnSendBytes != null)
{
OnSendBytes(this,flag,data);
}
return true;
}
catch(Exception e)
{
MessageBox.Show(e.Message);
return false;
}
}
以上是关于帮忙写一个C#例子:两个进程间通信的问题.的主要内容,如果未能解决你的问题,请参考以下文章