主题:[求助]C#服务器端与客户端数据传输(使用tcp异步套接字)
我很多不会写的地方在代码中注着。
其实最头痛的地方简单说就是:服务器如何判断客户端的不同请求,做出相应的处理。
还有1.是不是我们日常用的都是:服务器数据的发送都是基于客户端的请求。
2.客户端和服务器都定义了一个 StateObject类,
public class StateObject
{
public Socket workSocket = null; //客户套接字
public const int BufferSize = 1024; //缓冲区大小
public byte[] buffer = new byte[BufferSize]; //缓冲区
}
那么这个StateObject类所创建的对象 state 是不是可以理解为即将接收到的信息开辟一个空间,用来存储将要传递来的信息?
----------------------------
先将客户端的 登录窗体:
代码:
namespace openjjkh
{
public partial class enter : Form
{
public enter()
{
InitializeComponent();
}
private StateObject state;
private void enter_Load(object sender, EventArgs e)
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5555);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), clientSocket);
}
catch (Exception ee)
{
Console.WriteLine(ee.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
//传输多个textBox里的信息,Send()方法是不是用多参Send(textBox1.Text,textBox2.Text,1)
//1 代表服务器端 接受后要采用的相应的处理方法。
Send(textBox1.Text);
Send(textBox2.Text);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
clientSocket.EndConnect(ar);
state = new StateObject();
state.workSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.workSocket;
int bytesRead = clientSocket.EndReceive(ar);
if (bytesRead = 1) //这里是当信息被传送回来
{
khwindow khzct = new khwindow();
khzct.Show();
this.Hide();
}
else
{
MessageBox.Show("用户名或密码输入错误!!!");
textBox1.Text = "";
textBox2.Text = "";
}
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
private void Send(string data)
{
/*是否要给Send()在加个参数n,用来传递发送的是哪一类数据,服务器接收后根据这个参数执行相应的处理方法
比如现在是Send(string date,int n)
* 但传递的是 用户名和密码...我是不是要写成Send(string date1,string date2,int n)
* 这样下面就是:
* byte[] byteData1 = Encoding.Unicode.GetBytes(data1);
state.workSocket.BeginSend(byteData1, 0, byteData1.Length, 0, new AsyncCallback(SendCallback), state);
* byte[] byteData2 = Encoding.Unicode.GetBytes(data2);
state.workSocket.BeginSend(byteData2, 0, byteData2.Length, 0, new AsyncCallback(SendCallback), state);
* byte[] byteData3 = Encoding.Unicode.GetBytes(n);
state.workSocket.BeginSend(n, 0, n.Length, 0, new AsyncCallback(SendCallback), state);
* 这样写行不行,是不是太麻烦了,要是要同时发送10几个textBox里的数据启不是要写10几个参数吗,能不能写到一起啊?
*/
byte[] byteData = Encoding.Unicode.GetBytes(data);
state.workSocket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), state);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
int bytesSent = clientSocket.EndSend(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void label4_Click(object sender, EventArgs e)
{
/*此处点击这个label是弹出个新窗体,让客户端用户进行注册,
此时新窗体打开后,是否还需要进行连接?
* 假如在入口函数中采用判断,比如服务器发送来用户的用户名和密码被验证正确,登录了主窗体(而不是注册弹出的窗体),登录窗体Close(),
* 那在主窗体中是否要重新在进行连接?如果登录窗体时Hide(),是不是就不用了?
*/
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
}
}
在服务器端 主窗体:
代码:
namespace openjjsys
{
public partial class fwzwindow : Form
{
public fwzwindow()
{
InitializeComponent();
}
private StateObject state;
private void fwzwindow_Load(object sender, EventArgs e)
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5555);
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
serverSocket.Bind(localEndPoint);
serverSocket.Listen(100);
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
}
catch (Exception ee)
{
Console.WriteLine(ee.ToString());
}
}
public void AcceptCallback(IAsyncResult ar)
{
Socket serverSocket = (Socket)ar.AsyncState;
Socket clientSocket = serverSocket.EndAccept(ar);
state = new StateObject();
state.workSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
private void Send(string data)
{
byte[] byteData = Encoding.Unicode.GetBytes(data);
state.workSocket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), state);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
int bytesSent = clientSocket.EndSend(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.workSocket;
int bytesRead = clientSocket.EndReceive(ar);
/*这里需要判断 用户发送来的信息是哪一类的。
* 比如当bytesRead=1的时候表示:客户端上用户点击了登录,发送的是用户名和密码,此刻要执行查询数据库,返回验证结果。
如果当bytesRead=2时表示:客户端上用户点击注册,发送了个人的相关信息,服务器要将这些数据添加到数据库,返回注册结果。
当bytesRead=3时表示:用户以进入客户端主程序后点击一个button,弹出一个新窗体,发送的是要在新窗体的dataGirdView控件中显示他个人信息的请求,
* 服务器查询数据库,将相应的信息发回去...
* bytesRead=4 ......等等.......
*
* 在这里是不是这么写?而且clientSocket.EndReceive(ar)最终接收的应该是一组数据信息,它应该把这些信息分开。这里有点晕... 还有那些处理方法写在不同的函数体里调用, 还是把整个放在一个类里?
*
*/
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
private void fwzwindow_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
state.workSocket.Shutdown(SocketShutdown.Both);
state.workSocket.Close();
}
catch (Exception) { }
}
private void button1_Click(object sender, EventArgs e)
{
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
}
}