Winsock server/client 在 c# 中的应用
Winsock server/client application in c#
我正在使用 winsock 控件在 C# 中制作一个 Client/Server 应用程序。我做了其中的每一件事,但我坚持将数据从客户端发送到服务器的地方。在我的程序服务器中,始终使用 ip 和端口侦听客户端。我将数据从客户端发送到服务器。
1)单击服务器窗体上的监听按钮时,它会打开客户端连接的服务器。
2) 在客户端表单中,我第一次点击连接按钮,表示服务器已连接。为此消息提供一条消息(连接事件:ip),我们很容易知道客户端已连接到服务器。
3)然后我们在发送数据文本框中输入一些数据,然后点击发送按钮将数据发送到服务器并保存在客户端。
代码如下:
服务器:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Net.Sockets;
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const string DEFAULT_SERVER = "ip";
const int DEFAULT_PORT = 120;
System.Net.Sockets.Socket serverSocket;
System.Net.Sockets.SocketInformation serverSocketInfo;
public string Startup()
{
IPHostEntry hostInfo = Dns.GetHostByName(DEFAULT_SERVER);
IPAddress serverAddr = hostInfo.AddressList[0];
var serverEndPoint = new IPEndPoint(serverAddr, DEFAULT_PORT);
serverSocket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
serverSocket.Bind(serverEndPoint);
return serverSocket.LocalEndPoint.ToString();
}
public string Listen()
{
int backlog = 0;
try
{
serverSocket.Listen(backlog);
return "Server listening";
}
catch (Exception ex)
{
return "Failed to listen" + ex.ToString();
}
}
public string ReceiveData()
{
System.Net.Sockets.Socket receiveSocket;
byte[] buffer = new byte[256];
receiveSocket = serverSocket.Accept();
var bytesrecd = receiveSocket.Receive(buffer);
receiveSocket.Close();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
return encoding.GetString(buffer);
}
private void Listen_Click(object sender, EventArgs e)
{
string serverInfo = Startup();
textBox1.Text = "Server started at:" + serverInfo;
serverInfo = Listen();
textBox1.Text = serverInfo;
//string datatosend = Console.ReadLine();
//SendData(datatosend);
serverInfo = ReceiveData();
textBox1.Text = serverInfo;
//Console.ReadLine();
}
private void winsock_DataArrival(object sender, AxMSWinsockLib.DMSWinsockControlEvents_DataArrivalEvent e)
{
ReceiveData();
Listen();
}
private void winsock_ConnectEvent(object sender, EventArgs e)
{
Listen();
}
}
}
这一切都工作得很好但是我的问题是我只能一次从客户端获取数据到服务器。当我再次从客户端向服务器发送数据时,它不工作并给我一些消息,比如
Additional information: Only one usage of each socket address
(protocol/network address/port) is normally permitted
在服务器表单中
serverSocket.Bind(serverEndPoint);
请有人帮我解决我的问题。
谢谢。
我不是 100% 确定你理解 TCP 套接字所以这里开始。
当您使用 TCP 侦听器套接字时,您首先绑定到一个端口,以便客户端可以连接到一个固定的已知点。这将为您的套接字保留端口,直到您通过在该套接字上调用 Close()
放弃它。
接下来您要监听以开始在您绑定的端口上接受客户端的过程。您可以同时执行此操作和其中的第一步,但由于您没有,所以我没有在这里。
接下来你打电话给 Accept()
。这会阻塞(停止执行)直到客户端连接,然后它 returns 一个专用于与该客户端通信的套接字。如果你想允许另一个客户端连接,你必须再次调用Accept()
。
然后您可以使用 Accept()
返回的套接字与您的客户端通信,直到完成为止,此时您可以在该套接字上调用 Close()
。
当您完成新连接的监听后,您可以在监听器套接字上调用 Close()
。
然而,当您按下收听按钮时,会发生以下情况:
您正确绑定,开始正确收听,然后您对 ReceiveData()
的调用会阻塞 Accept 调用,直到收到客户端。然后您会收到一些数据(虽然这是 TCP,所以可能不是全部数据!)然后您立即关闭与客户端的连接。
我想得到了你得到的错误,你必须在你的服务器上再次按下监听。因此,这会重新启动整个侦听器套接字,当您第二次绑定到该端口时,您之前的侦听器仍然绑定到它,因此调用失败,因为该端口上已经分配了一些东西。
明智的解决方案是您需要保持从 Accept()
调用返回的套接字处于打开状态,直到您完成它。让客户端通过在其套接字上调用 Shutdown()
方法来处理关闭,或者建立一些约定来标记通信结束。
当您尝试连接多个用户时,您也会 运行 遇到麻烦,因此在某些时候您将需要线程或一些异步套接字,但我觉得这超出了范围这个问题。
试试这个。对你有帮助
delegate void AddTextCallback(string text);
public Form1()
{
InitializeComponent();
}
private void ButtonConnected_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ServerHandler));
}
private void ServerHandler(object state)
{
TcpListener _listner = new TcpListener(IPAddress.Parse("12.2.54.658"), 145);
_listner.Start();
AddText("Server started - Listening on port 145");
Socket _sock = _listner.AcceptSocket();
//AddText("User from IP " + _sock.RemoteEndPoint);
while (_sock.Connected)
{
byte[] _Buffer = new byte[1024];
int _DataReceived = _sock.Receive(_Buffer);
if (_DataReceived == 0)
{
break;
}
AddText("Message Received...");
string _Message = Encoding.ASCII.GetString(_Buffer);
AddText(_Message);
}
_sock.Close();
AddText("Client Disconnected.");
_listner.Stop();
AddText("Server Stop.");
}
private void AddText(string text)
{
if (this.listBox1.InvokeRequired)
{
AddTextCallback d = new AddTextCallback(AddText);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
}
}
上个月我也遇到了和你一样的问题,但我使用来自 Whosebug 的 Receive multiple different messages TcpListener C# 解决了这个问题。这对我很有帮助希望它也能帮助解决你的问题。
我建议您不要使用 AxMSWinsockLib。请查看此处给出的套接字示例,其中显示了如何创建客户端套接字和服务器套接字 - https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx AND this one - https://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx
我正在使用 winsock 控件在 C# 中制作一个 Client/Server 应用程序。我做了其中的每一件事,但我坚持将数据从客户端发送到服务器的地方。在我的程序服务器中,始终使用 ip 和端口侦听客户端。我将数据从客户端发送到服务器。
1)单击服务器窗体上的监听按钮时,它会打开客户端连接的服务器。
2) 在客户端表单中,我第一次点击连接按钮,表示服务器已连接。为此消息提供一条消息(连接事件:ip),我们很容易知道客户端已连接到服务器。
3)然后我们在发送数据文本框中输入一些数据,然后点击发送按钮将数据发送到服务器并保存在客户端。
代码如下:
服务器:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Net.Sockets;
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const string DEFAULT_SERVER = "ip";
const int DEFAULT_PORT = 120;
System.Net.Sockets.Socket serverSocket;
System.Net.Sockets.SocketInformation serverSocketInfo;
public string Startup()
{
IPHostEntry hostInfo = Dns.GetHostByName(DEFAULT_SERVER);
IPAddress serverAddr = hostInfo.AddressList[0];
var serverEndPoint = new IPEndPoint(serverAddr, DEFAULT_PORT);
serverSocket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
serverSocket.Bind(serverEndPoint);
return serverSocket.LocalEndPoint.ToString();
}
public string Listen()
{
int backlog = 0;
try
{
serverSocket.Listen(backlog);
return "Server listening";
}
catch (Exception ex)
{
return "Failed to listen" + ex.ToString();
}
}
public string ReceiveData()
{
System.Net.Sockets.Socket receiveSocket;
byte[] buffer = new byte[256];
receiveSocket = serverSocket.Accept();
var bytesrecd = receiveSocket.Receive(buffer);
receiveSocket.Close();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
return encoding.GetString(buffer);
}
private void Listen_Click(object sender, EventArgs e)
{
string serverInfo = Startup();
textBox1.Text = "Server started at:" + serverInfo;
serverInfo = Listen();
textBox1.Text = serverInfo;
//string datatosend = Console.ReadLine();
//SendData(datatosend);
serverInfo = ReceiveData();
textBox1.Text = serverInfo;
//Console.ReadLine();
}
private void winsock_DataArrival(object sender, AxMSWinsockLib.DMSWinsockControlEvents_DataArrivalEvent e)
{
ReceiveData();
Listen();
}
private void winsock_ConnectEvent(object sender, EventArgs e)
{
Listen();
}
}
}
这一切都工作得很好但是我的问题是我只能一次从客户端获取数据到服务器。当我再次从客户端向服务器发送数据时,它不工作并给我一些消息,比如
Additional information: Only one usage of each socket address (protocol/network address/port) is normally permitted
在服务器表单中
serverSocket.Bind(serverEndPoint);
请有人帮我解决我的问题。
谢谢。
我不是 100% 确定你理解 TCP 套接字所以这里开始。
当您使用 TCP 侦听器套接字时,您首先绑定到一个端口,以便客户端可以连接到一个固定的已知点。这将为您的套接字保留端口,直到您通过在该套接字上调用 Close()
放弃它。
接下来您要监听以开始在您绑定的端口上接受客户端的过程。您可以同时执行此操作和其中的第一步,但由于您没有,所以我没有在这里。
接下来你打电话给 Accept()
。这会阻塞(停止执行)直到客户端连接,然后它 returns 一个专用于与该客户端通信的套接字。如果你想允许另一个客户端连接,你必须再次调用Accept()
。
然后您可以使用 Accept()
返回的套接字与您的客户端通信,直到完成为止,此时您可以在该套接字上调用 Close()
。
当您完成新连接的监听后,您可以在监听器套接字上调用 Close()
。
然而,当您按下收听按钮时,会发生以下情况:
您正确绑定,开始正确收听,然后您对 ReceiveData()
的调用会阻塞 Accept 调用,直到收到客户端。然后您会收到一些数据(虽然这是 TCP,所以可能不是全部数据!)然后您立即关闭与客户端的连接。
我想得到了你得到的错误,你必须在你的服务器上再次按下监听。因此,这会重新启动整个侦听器套接字,当您第二次绑定到该端口时,您之前的侦听器仍然绑定到它,因此调用失败,因为该端口上已经分配了一些东西。
明智的解决方案是您需要保持从 Accept()
调用返回的套接字处于打开状态,直到您完成它。让客户端通过在其套接字上调用 Shutdown()
方法来处理关闭,或者建立一些约定来标记通信结束。
当您尝试连接多个用户时,您也会 运行 遇到麻烦,因此在某些时候您将需要线程或一些异步套接字,但我觉得这超出了范围这个问题。
试试这个。对你有帮助
delegate void AddTextCallback(string text);
public Form1()
{
InitializeComponent();
}
private void ButtonConnected_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ServerHandler));
}
private void ServerHandler(object state)
{
TcpListener _listner = new TcpListener(IPAddress.Parse("12.2.54.658"), 145);
_listner.Start();
AddText("Server started - Listening on port 145");
Socket _sock = _listner.AcceptSocket();
//AddText("User from IP " + _sock.RemoteEndPoint);
while (_sock.Connected)
{
byte[] _Buffer = new byte[1024];
int _DataReceived = _sock.Receive(_Buffer);
if (_DataReceived == 0)
{
break;
}
AddText("Message Received...");
string _Message = Encoding.ASCII.GetString(_Buffer);
AddText(_Message);
}
_sock.Close();
AddText("Client Disconnected.");
_listner.Stop();
AddText("Server Stop.");
}
private void AddText(string text)
{
if (this.listBox1.InvokeRequired)
{
AddTextCallback d = new AddTextCallback(AddText);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
}
}
上个月我也遇到了和你一样的问题,但我使用来自 Whosebug 的 Receive multiple different messages TcpListener C# 解决了这个问题。这对我很有帮助希望它也能帮助解决你的问题。
我建议您不要使用 AxMSWinsockLib。请查看此处给出的套接字示例,其中显示了如何创建客户端套接字和服务器套接字 - https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx AND this one - https://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx