Socket单客户端/服务器连接,服务器可以多次发送,客户端只能发一次

我编写了一个客户端和服务器应用程序,我需要用它来连接我用C#制作的跳棋游戏。 我有连接的客户端和服务器,服务器可以重复发送客户端消息来更新标签但是当客户端尝试发送消息时它会抛出错误

“由于没有连接套接字而且(当使用sendto调用在数据报套接字上发送时)没有提供地址,因此不允许发送或接收数据的请求。”

到目前为止,这是我的客户端和服务器。

客户 –

public partial class Form1 : Form //main form that establishes connection { Form2 form2 = new Form2(); Socket sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Socket acc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint endPoint; static byte[] Buffer { get; set; } string text; public Form1() { InitializeComponent(); } private void button1_Click_1(object sender, EventArgs e) { Thread rec = new Thread(recMsg); Thread t = new Thread(ThreadProc); t.Start(); //starts a form that will call the sendMsg on a button click endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8887); try { sck.Connect(endPoint); } catch { Console.WriteLine("unable to connect"); } rec.Start(); text = textBox1.Text; sendMsg(text); } public void sendMsg(string s) { //bool x = true; //while (true) //{ //Thread.Sleep(500); //if (x == true) //{ byte[] msgBuffer = Encoding.ASCII.GetBytes(s); sck.Send(msgBuffer); //error comes here when i try to send a message from form2 says it isn't connected and has no address // x = false; //} //} the commented out part doesn't effect how the send works it sends once and can't again, I think the problem is that the thread which establishes the connection dies but don't know how to solve. } public void recMsg() { while (true) { Thread.Sleep(500); byte[] Buffer = new byte[255]; int rec = sck.Receive(Buffer, 0, Buffer.Length, 0); Array.Resize(ref Buffer, rec); form2.SetText(Encoding.Default.GetString(Buffer)); } } private void button2_Click(object sender, EventArgs e) { sck.Close(); } public void ThreadProc() { form2.ShowDialog(); } } 

表单2具有label1,textbox1和button1,主要操作表单将接受输入并调用Form1 sendMsg()

 public partial class Form2 : Form { delegate void SetTextCallback(string text); Form1 form1; public Form2() { InitializeComponent(); } public void SetText(string text) { if (InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); Invoke(d, new object[] { text }); } else { label1.Text = text; } } private void button1_Click(object sender, EventArgs e) { form1 = new Form1(); form1.sendMsg(textBox1.Text); } } 

服务器-

 class Program { static Form1 form1 = new Form1(); static Form2 form2 = new Form2(); static byte[] buffer { get; set; } static Socket sck, acc; static string name; static void Main(string[] args) { if (name == null) { Thread t = new Thread(ThreadProc); t.Start(); } Thread rec = new Thread(recMsg); sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sck.Bind(new IPEndPoint(0, 8887)); Console.WriteLine("Your local IP address is: " + getIP()); Console.WriteLine("Awaiting Connection"); sck.Listen(0); acc = sck.Accept(); Console.WriteLine(" >> Accept connection from client"); rec.Start(); sendMsg(); } static string getIP() { string hostName = System.Net.Dns.GetHostName(); IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostName); IPAddress[] addr = ipEntry.AddressList; return addr[addr.Length - 1].ToString(); } static void recMsg() { while (acc.Connected) { Thread.Sleep(500); byte[] Buffer = new byte[255]; int rec = acc.Receive(Buffer, 0, Buffer.Length, 0); Array.Resize(ref Buffer, rec); form2.SetText(Encoding.Default.GetString(Buffer)); } } public void btnClick(string s) { name = s; Console.WriteLine("Name: " + name); System.Threading.Thread r = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadProc2)); r.Start(); } public void sendMSG(string s) { try { buffer = Encoding.Default.GetBytes(s); acc.Send(buffer); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } static void sendMsg() { try { buffer = Encoding.Default.GetBytes(name); acc.Send(buffer); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } public static void ThreadProc() { form1.ShowDialog(); } public static void ThreadProc2() { form2.ShowDialog(); } } 

Form1 – 要求输入名称的初学者表单,这个表单可能只是用来构建我的基本服务器,这最终将成为跳棋游戏所需要的。

 public partial class Form1 : Form { Program program; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { this.Hide(); program = new Program(); program.btnClick(textBox1.Text); } } 

Form2用作我客户端Form2的接口,基本上有一个标签,文本框和调用sendMsg()的按钮

 public partial class Form2 : Form { delegate void SetTextCallback(string text); Program program = new Program(); public Form2() { InitializeComponent(); } public void SetText(string text) { if (InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.label2.Text = text; } } private void button1_Click(object sender, EventArgs e) { program.sendMSG(textBox1.Text); } } 

回顾一下,该程序将连接,服务器可以多次向客户端发送数据并更新标签。 客户端将在第一次向服务器发送数据,然后抛出错误。

为什么不使用异步套接字? 这是一些代码:

 // Server socket class ControllerSocket : Socket, IDisposable { // MessageQueue queues messages to be processed by the controller public Queue messageQueue = null; // This is a list of all attached clients public List clients = new List(); #region Events // Event definitions handled in the controller public delegate void SocketConnectedHandler(Socket socket); public event SocketConnectedHandler SocketConnected; public delegate void DataRecievedHandler(Socket socket, int bytesRead); public event DataRecievedHandler DataRecieved; public delegate void DataSentHandler(Socket socket, int length); public event DataSentHandler DataSent; public delegate void SocketDisconnectedHandler(); public event SocketDisconnectedHandler SocketDisconnected; #endregion #region Constructor public ControllerSocket(int port) : base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { // Create the message queue this.messageQueue = new Queue(); // Acquire the host address and port, then bind the server socket IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipAddress = ipHostInfo.AddressList[0]; IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port); this.Bind(localEndPoint); } #endregion // Starts accepting client connections public void StartListening() { this.Listen(100); this.BeginAccept(AcceptCallback, this); } // Connects to a client private void AcceptCallback(IAsyncResult ar) { Socket listener = (Socket)ar.AsyncState; Socket socket = listener.EndAccept(ar); try { // Add the connected client to the list clients.Add(socket); // Notify any event handlers if (SocketConnected != null) SocketConnected(socket); // Create an initial state object to hold buffer and socket details StateObject state = new StateObject(); state.workSocket = socket; state.BufferSize = 8192; // Begin asynchronous read socket.BeginReceive(state.Buffer, 0, state.BufferSize, 0, ReadCallback, state); } catch (SocketException) { HandleClientDisconnect(socket); } finally { // Listen for more client connections StartListening(); } } // Read data from the client private void ReadCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; Socket socket = state.workSocket; try { if (socket.Connected) { // Read the socket int bytesRead = socket.EndReceive(ar); // Deserialize objects foreach (MessageBase msg in MessageBase.Receive(socket, bytesRead, state)) { // Add objects to the message queue lock (this.messageQueue) messageQueue.Enqueue(msg); } // Notify any event handlers if (DataRecieved != null) DataRecieved(socket, bytesRead); // Asynchronously read more client data socket.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReadCallback, state); } else { HandleClientDisconnect(socket); } } catch (SocketException) { HandleClientDisconnect(socket); } } // Send data to a specific client public void Send(Socket socket, MessageBase msg) { try { // Serialize the message byte[] bytes = msg.Serialize(); if (socket.Connected) { // Send the message socket.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, socket); } else { HandleClientDisconnect(socket); } } catch (SocketException) { HandleClientDisconnect(socket); } } // Broadcast data to all clients public void Broadcast(MessageBase msg) { try { // Serialize the message byte[] bytes = msg.Serialize(); // Process all clients foreach (Socket client in clients) { try { // Send the message if (client.Connected) { client.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, client); } else { HandleClientDisconnect(client); } } catch (SocketException) { HandleClientDisconnect(client); } } } catch (Exception e) { // Serialization error Console.WriteLine(e.ToString()); } } // Data sent to a client socket private void SendCallback(IAsyncResult ar) { try { Socket socket = (Socket)ar.AsyncState; if (socket.Connected) { // Complete sending the data int bytesSent = socket.EndSend(ar); // Notify any attached handlers if (DataSent != null) DataSent(socket, bytesSent); } else { HandleClientDisconnect(socket); } } catch (Exception e) { Console.WriteLine(e.ToString()); } } private void HandleClientDisconnect(Socket client) { // Client socket may have shutdown unexpectedly if (client.Connected) client.Shutdown(SocketShutdown.Both); // Close the socket and remove it from the list client.Close(); clients.Remove(client); // Notify any event handlers if (SocketDisconnected != null) SocketDisconnected(); } // Close all client connections public void Dispose() { foreach (Socket client in clients) { if (client.Connected) client.Shutdown(SocketShutdown.Receive); client.Close(); } } } // Client socket class ReceiverSocket : Socket { // MessageQueue queues messages to be processed by the controller public Queue messageQueue = null; #region Events // Event definitions handled in the controller public delegate void SocketConnectedHandler(Socket socket); public event SocketConnectedHandler SocketConnected; public delegate void DataRecievedHandler(Socket socket, MessageBase msg); public event DataRecievedHandler DataRecieved; public delegate void DataSentHandler(Socket socket, int length); public event DataSentHandler DataSent; public delegate void SocketDisconnectedHandler(); public event SocketDisconnectedHandler SocketDisconnected; private IPEndPoint remoteEP = null; #endregion #region Constructor public ReceiverSocket(int port) : base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { // Create the message queue messageQueue = new Queue(); // Acquire the host address and port IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipAddress = ipHostInfo.AddressList[0]; remoteEP = new IPEndPoint(ipAddress, port); } #endregion // Connect to the server public void Connect() { this.BeginConnect(remoteEP, ConnectCallback, this); } // Server connected private void ConnectCallback(IAsyncResult ar) { // Console.WriteLine("Connect Callback"); try { Socket client = (Socket)ar.AsyncState; if (client.Connected) { client.EndConnect(ar); // Console.WriteLine("Connect Callback - Connected"); // Create an initial state object to hold buffer and socket details StateObject state = new StateObject(); state.workSocket = client; state.BufferSize = 8192; // Notify any event handlers if (SocketConnected != null) SocketConnected(client); // Begin asynchronous read client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state); } else { // Console.WriteLine("Connect Callback - Reconnect"); Thread.Sleep(5000); Connect(); } } catch (Exception ex) { // Attempt server reconnect Reconnect(); } } // Read data from the server private void ReceiveCallback(IAsyncResult ar) { try { StateObject state = (StateObject)ar.AsyncState; Socket client = state.workSocket; // Read the socket if (client.Connected) { int bytesRead = client.EndReceive(ar); // Deserialize objects foreach (MessageBase msg in MessageBase.Receive(client, bytesRead, state)) { // Add objects to the message queue lock (this.messageQueue) this.messageQueue.Enqueue(msg); } // Notify any event handlers if (DataRecieved != null) DataRecieved(client, null); // Asynchronously read more server data client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state); } else { Reconnect(); } } catch (SocketException) { // Attempt server reconnect Reconnect(); } } public void Send(MessageBase msg) { try { // Serialize the message byte[] bytes = msg.Serialize(); if (this.Connected) { // Send the message this.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, this); } else { Reconnect(); } } catch (SocketException sox) { // Attempt server reconnect Reconnect(); } catch (Exception ex) { int i = 0; } } private void SendCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; if (client.Connected) { // Complete sending the data int bytesSent = client.EndSend(ar); // Notify any event handlers if (DataSent != null) DataSent(client, bytesSent); } else { Reconnect(); } } catch (SocketException) { Reconnect(); } } // Attempt to reconnect to the server private void Reconnect() { try { // Disconnect the original socket if (this.Connected) this.Disconnect(true); this.Close(); // Notify any event handlers if (SocketDisconnected != null) SocketDisconnected(); } catch (Exception e) { // Console.WriteLine(e.ToString()); } } } // Encapsulates information about the socket and data buffer public class StateObject { public Socket workSocket = null; public int readOffset = 0; public StringBuilder sb = new StringBuilder(); private int bufferSize = 0; public int BufferSize { set { this.bufferSize = value; buffer = new byte[this.bufferSize]; } get { return this.bufferSize; } } private byte[] buffer = null; public byte[] Buffer { get { return this.buffer; } } } 

您需要做的就是插入自己的消息。

请记住,套接字流可能(并且大多数情况下)包含部分消息。 因此,最好将消息的长度作为消息的第一个字节发送。 您还必须通过在读取之间组合部分消息来相应地管理读取缓冲区。 查看以下消息基类。

 public partial class MessageBase { // Virtual Execute method following the Command pattern public virtual string Execute(Socket socket) { return string.Empty; } protected virtual bool MustEncrypt { get { return false; } } // Binary serialization public byte[] Serialize() { using (MemoryStream stream = new MemoryStream()) { using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Compress, true)) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(ds, this); ds.Flush(); } byte[] bytes = stream.GetBuffer(); byte[] bytes2 = new byte[stream.Length]; Buffer.BlockCopy(bytes, 0, bytes2, 0, (int)stream.Length); // Array.Copy(bytes, bytes2, stream.Length); if (this.MustEncrypt) bytes2 = RijndaelEncrptor.Instance.Encrypt(bytes2); // Create a buffer large enough to hold the encrypted message and size bytes byte[] data = new byte[8 + bytes2.Length]; // Add the message size BitConverter.GetBytes(bytes2.Length).CopyTo(data, 0); BitConverter.GetBytes(this.MustEncrypt).CopyTo(data, 4); // Add the message data bytes2.CopyTo(data, 8); return data; } } static public MessageBase Deserialize(byte[] buffer) { int length = BitConverter.ToInt32(buffer, 0); bool mustDecrypt = BitConverter.ToBoolean(buffer, 4); MessageBase b = null; try { b = MessageBase.Deserialize(buffer, 8, length, mustDecrypt); } catch { } return b; } static public MessageBase Deserialize(byte[] buffer, int offset, int length, bool mustDecrypt) { // Create a buffer and initialize it with data from // the input buffer offset by the specified offset amount // and length determined by the specified length byte[] data = new byte[length]; Buffer.BlockCopy(buffer, offset, data, 0, length); // Array.Copy(buffer, offset, data, 0, length); // Decrypt message if (mustDecrypt) data = RijndaelEncrptor.Instance.Decrypt(data); // Deserialize the binary data into a new object of type MessageBase using (MemoryStream stream = new MemoryStream(data)) { using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Decompress, false)) { BinaryFormatter formatter = new BinaryFormatter(); try { return formatter.Deserialize(ds) as MessageBase; } catch { return null; } } } } static public IEnumerable Receive(Socket client, int bytesReceived, StateObject state) { // Total buffered count is the bytes received this read // plus any unprocessed bytes from the last receive int bufferLen = bytesReceived + state.readOffset; // Reset the next read offset in the case // this recieve lands on a message boundary state.readOffset = 0; // Make sure there are bytes to read if (bufferLen >= 0) { // Initialize the current read position int readOffset = 0; // Process the receive buffer while (readOffset < bufferLen) { // Get the message size int length = BitConverter.ToInt32(state.Buffer, readOffset); bool mustDecrypt = BitConverter.ToBoolean(state.Buffer, readOffset + 4); // Increment the current read position by the length header readOffset += 8; // Change the buffer size if necessary if (length + readOffset > state.Buffer.Length) { byte[] oldBuffer = new byte[state.BufferSize]; Buffer.BlockCopy(state.Buffer, 0, oldBuffer, 0, state.BufferSize); // Array.Copy(state.Buffer, oldBuffer, state.BufferSize); state.BufferSize = length + readOffset; Buffer.BlockCopy(oldBuffer, 0, state.Buffer, 0, oldBuffer.Length); // Array.Copy(oldBuffer, state.Buffer, oldBuffer.Length); } // Ensure there are enough bytes to process the message if (readOffset + length <= bufferLen) yield return MessageBase.Deserialize(state.Buffer, readOffset, length, mustDecrypt); else { // Add back the message length readOffset -= 8; // Reorder the receive buffer so unprocessed // bytes are moved to the start of the array Buffer.BlockCopy(state.Buffer, 0, state.Buffer, 0, bufferLen - readOffset); // Array.Copy(state.Buffer, state.Buffer, bufferLen - readOffset); // Set the receive position to the current read position // This is the offset where the next socket read will start state.readOffset = bufferLen - readOffset; break; } // Update the read position by the message length readOffset += length; } } } } 

上面的代码可以帮到你。

您确实意识到您的代码永远不会从此处退出:

 public void sendMsg(string s) { bool x = true; while (true) { Thread.Sleep(500); if (x == true) { byte[] msgBuffer = Encoding.ASCII.GetBytes(s); sck.Send(msgBuffer); x = false; } } } 

这是一个无限循环,没有rest或返回,也没有办法退出。 怎么样:

 public void sendMsg(string s) { while (true) { Thread.Sleep(500); byte[] msgBuffer = Encoding.ASCII.GetBytes(s); sck.Send(msgBuffer); } } 

想出一个解决我的问题的方法可能不是标准的方法,但它有效。 这是一个简单的聊天应用程序,可用于连接玩家与玩家游戏在线发送来回移动。

服务器-

 using System; using System.Net.Sockets; using System.Text; using System.Net; using System.Threading; using System.Windows.Forms; namespace testServer { class Program { static Form1 form1 = new Form1(); static Form2 form2 = new Form2(); static byte[] buffer { get; set; } static Socket sck, acc; static string name; public void setName(string s) { name = s; string[] asdf = new string[2]; } static string getIP() { string hostName = System.Net.Dns.GetHostName(); IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostName); IPAddress[] addr = ipEntry.AddressList; return addr[addr.Length - 1].ToString(); } static void Main(string[] args) { if (name == null) { Thread t = new Thread(ThreadProc); t.Start(); } sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sck.Bind(new IPEndPoint(0, 8888)); Console.WriteLine("Your local IP address is: " + getIP()); Console.WriteLine("Awaiting Connection"); sck.Listen(100); acc = sck.Accept(); Console.WriteLine(" >> Accept connection from client"); sendMsg(); while (acc.Connected) { Thread.Sleep(500); byte[] Buffer = new byte[255]; int receive = acc.Receive(Buffer, 0, Buffer.Length, 0); Array.Resize(ref Buffer, receive); form2.SetText(Encoding.Default.GetString(Buffer)); } } public void btnClick(string s) { name = s; Console.WriteLine("Name: " + name); System.Threading.Thread r = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadProc2)); r.Start(); } public void sendMSG(string s) { try { buffer = Encoding.Default.GetBytes(s); acc.Send(buffer); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } static void sendMsg() { try { buffer = Encoding.Default.GetBytes(name); acc.Send(buffer); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } public static void ThreadProc() { form1.ShowDialog(); } public static void ThreadProc2() { form2.ShowDialog(); } } } 

这是程序类,其他forms与我原来的post相同。

客户-

 using System; using System.Windows.Forms; using System.Text; using System.Net.Sockets; using System.Threading; namespace testClient100 { public partial class Form1 : Form { System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient(); NetworkStream serverStream = default(NetworkStream); string readData = null; string ipaddress; public Form1() { InitializeComponent(); } private void getMessage() { while (true) { serverStream = clientSocket.GetStream(); int buffSize = 0; byte[] inStream = new byte[10025]; buffSize = clientSocket.ReceiveBufferSize; serverStream.Read(inStream, 0, buffSize); string returndata = System.Text.Encoding.ASCII.GetString(inStream); readData = "" + returndata; msg(); } } private void msg() { if (this.InvokeRequired) this.Invoke(new MethodInvoker(msg)); else textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + readData; } private void button1_Click_1(object sender, EventArgs e) { byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); } private void button2_Click_1(object sender, EventArgs e) { ipaddress = textBox4.Text; readData = "Conected to Chat Server ..."; msg(); clientSocket.Connect(ipaddress, 8888); serverStream = clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox3.Text); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); Thread ctThread = new Thread(getMessage); ctThread.Start(); } } }