我设法创建了一个服务器/客户端聊天系统,客户端向服务器发送消息,服务器将消息发送给所有客户端。
我想对此进行扩展,以便服务器比较消息,然后向客户端发送消息。
例如:如果客户端1发送10而客户端2发送20,则服务器将比较这些,服务器将发送一条消息,表示20超过10。
这可能吗?如果是这样的话?
服务器代码:
namespace Server
{
public partial class Form1 : Form
{
private const int m_iMaxConnections = 2;
struct Connection_Struct // Define a structure to hold details about a single connection
{
public Socket ClientSpecific_Socket;
public bool bInUse;
};
Socket m_ListenSocket;
Socket m_SendSocket;
Connection_Struct[] m_Connection_Array = new Connection_Struct[m_iMaxConnections]; // Define an array to hold a number of connections
System.Net.IPEndPoint m_LocalIPEndPoint;
static int m_iNumberOfConnectedClients;
private static System.Windows.Forms.Timer m_CommunicationActivity_Timer;
public Form1()
{
InitializeComponent();
Initialise_ConnectionArray();
m_CommunicationActivity_Timer = new System.Windows.Forms.Timer(); // Check for communication activity on Non-Blocking sockets every 200ms
m_CommunicationActivity_Timer.Tick += new EventHandler(OnTimedEvent_PeriodicCommunicationActivityCheck); // Set event handler method for timer
m_CommunicationActivity_Timer.Interval = 100; // Timer interval is 1/10 second
m_CommunicationActivity_Timer.Enabled = false;
string szLocalIPAddress = GetLocalIPAddress_AsString(); // Get local IP address as a default value
txtIPAddress.Text = szLocalIPAddress; // Place local IP address in IP address field
txtPort.Text = "8000"; // Default port number
m_iNumberOfConnectedClients = 0;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
try
{ // Create the Listen socket, for TCP use
m_ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ListenSocket.Blocking = false;
m_SendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Tcp);
}
catch (SocketException se)
{ // If an exception occurs, display an error message
MessageBox.Show(se.Message);
}
}
private void Initialise_ConnectionArray()
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
m_Connection_Array[iIndex].bInUse = false;
}
}
private void btnEnableServer_Click(object sender, EventArgs e)
{
// Bind to the selected port and start listening / receiving
try
{
// Get the Port number from the appropriate text box
String szPort = txtPort.Text;
int iPort = System.Convert.ToInt16(szPort, 10);
// Create an Endpoint that will cause the listening activity to apply to all the local node's interfaces
m_LocalIPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, iPort);
// Bind to the local IP Address and selected port
m_ListenSocket.Bind(m_LocalIPEndPoint);
txtLog.Text = "Bind succeded";
// Prevent any further changes to the port number
txtPort.ReadOnly = true;
}
catch // Catch any errors
{ // If an exception occurs, display an error message
txtLog.Text = "Bind failed";
}
try
{
txtLog.Text = "Listening";
m_ListenSocket.Listen(2); // Listen for connections, with a backlog / queue maximum of 2
}
catch (SocketException se)
{
// If an exception occurs, display an error message
MessageBox.Show(se.Message);
}
catch // Silently handle any other exception
{
}
m_CommunicationActivity_Timer.Start(); // Start the timer to perform periodic checking for connection requests
txtLog.Text = "Accepting (waiting for connection attempt)";
btnEnableServer.Enabled = false;
}
private void OnTimedEvent_PeriodicCommunicationActivityCheck(Object myObject, EventArgs myEventArgs)
{ // Periodic check whether a connection request is pending or a message has been received on a connected socket
// First, check for pending connection requests
int iIndex;
iIndex = GetnextAvailable_ConnectionArray_Entry(); // Find an available array entry for next connection request
if (-1 != iIndex)
{ // Only continue with Accept if there is an array entry available to hold the details
try
{
m_Connection_Array[iIndex].ClientSpecific_Socket = m_ListenSocket.Accept(); // Accept a connection (if pending) and assign a new socket to it (AcceptSocket)
// Will 'catch' if NO connection was pending, so statements below only occur when a connection WAS pending
m_Connection_Array[iIndex].bInUse = true;
m_Connection_Array[iIndex].ClientSpecific_Socket.Blocking = false; // Make the new socket operate in non-blocking mode
m_iNumberOfConnectedClients++;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
txtLog.Text = "A new client connected";
SendUpdateMesageToAllConnectedclients();
}
catch (SocketException se) // Handle socket-related exception
{ // If an exception occurs, display an error message
if (10053 == se.ErrorCode || 10054 == se.ErrorCode) // Remote end closed the connection
{
CloseConnection(iIndex);
}
else if (10035 != se.ErrorCode)
{ // Ignore error messages relating to normal behaviour of non-blocking sockets
MessageBox.Show(se.Message);
}
}
catch // Silently handle any other exception
{
}
}
// Second, check for received messages on each connected socket
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
try
{
EndPoint localEndPoint = (EndPoint)m_LocalIPEndPoint;
byte[] ReceiveBuffer = new byte[1024];
int iReceiveByteCount;
iReceiveByteCount = m_Connection_Array[iIndex].ClientSpecific_Socket.ReceiveFrom(ReceiveBuffer, ref localEndPoint);
string szReceivedMessage;
if (0 < iReceiveByteCount)
{ // Copy the number of bytes received, from the message buffer to the text control
szReceivedMessage = Encoding.ASCII.GetString(ReceiveBuffer, 0, iReceiveByteCount);
if ("QuitConnection" == szReceivedMessage)
{
CloseConnection(iIndex);
}
else
{
txtLog.AppendText(szReceivedMessage + Environment.NewLine);
// Send message to each connected client.
// int iIndex2;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
string szMessage;
szMessage = szReceivedMessage;
txtLog.Text = m_Connection_Array[m_iMaxConnections].ToString();
byte[] SendMessage = System.Text.Encoding.ASCII.GetBytes(szMessage);
m_Connection_Array[iIndex].ClientSpecific_Socket.Send(SendMessage, SocketFlags.None);
}
}
}
}
}
catch (SocketException se) // Handle socket-related exception
{ // If an exception occurs, display an error message
if (10053 == se.ErrorCode || 10054 == se.ErrorCode) // Remote end closed the connection
{
CloseConnection(iIndex);
}
else if (10035 != se.ErrorCode)
{ // Ignore error messages relating to normal behaviour of non-blocking sockets
MessageBox.Show(se.Message);
}
}
catch // Silently handle any other exception
{
}
}
}
}
private void SendUpdateMesageToAllConnectedclients()
{ // Send message to each connected client informing of the total number of connected clients
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
string szMessage;
if (1 == m_iNumberOfConnectedClients)
{
szMessage = string.Format("There is now {0} client connected", m_iNumberOfConnectedClients);
}
else
{
szMessage = string.Format("There are now {0} clients connected", m_iNumberOfConnectedClients);
}
byte[] SendMessage = System.Text.Encoding.ASCII.GetBytes(szMessage);
m_Connection_Array[iIndex].ClientSpecific_Socket.Send(SendMessage, SocketFlags.None);
}
}
}
private void CloseConnection(int iIndex)
{
try
{
m_Connection_Array[iIndex].bInUse = false;
m_Connection_Array[iIndex].ClientSpecific_Socket.Shutdown(SocketShutdown.Both);
m_Connection_Array[iIndex].ClientSpecific_Socket.Close();
m_iNumberOfConnectedClients--;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
txtLog.Text = "A Connection was closed";
SendUpdateMesageToAllConnectedclients();
}
catch // Silently handle any exceptions
{
}
}
private void Close_And_Quit()
{ // Close the sockets and exit the application
try
{
m_ListenSocket.Close();
}
catch
{
}
try
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
m_Connection_Array[iIndex].ClientSpecific_Socket.Shutdown(SocketShutdown.Both);
m_Connection_Array[iIndex].ClientSpecific_Socket.Close();
}
}
catch
{
}
try
{
Close();
}
catch
{
}
}
public string GetLocalIPAddress_AsString()
{
string szHost = Dns.GetHostName();
string szLocalIPaddress = "127.0.0.1"; // Default is local loopback address
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress IP in IPHost.AddressList)
{
if (IP.AddressFamily == AddressFamily.InterNetwork) // Match only the IPv4 address
{
szLocalIPaddress = IP.ToString();
break;
}
}
return szLocalIPaddress;
}
private int GetnextAvailable_ConnectionArray_Entry()
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (false == m_Connection_Array[iIndex].bInUse)
{
return iIndex; // Return the index value of the first not-in-use entry found
}
}
return -1; // Signal that there were no available entries
}
}
}
客户代码:
namespace Client
{
public partial class Form1 : Form
{
Socket m_ClientSocket;
System.Net.IPEndPoint m_remoteEndPoint;
IPEndPoint m_localIPEndPoint;
Socket m_ReceiveSocket;
private static System.Windows.Forms.Timer m_CommunicationActivity_Timer;
public Form1()
{
InitializeComponent();
m_CommunicationActivity_Timer = new System.Windows.Forms.Timer(); // Check for communication activity on Non-Blocking sockets every 200ms
m_CommunicationActivity_Timer.Tick += new EventHandler(OnTimedEvent_PeriodicCommunicationActivityCheck); // Set event handler method for timer
m_CommunicationActivity_Timer.Interval = 100; // Timer interval is 1/10 second
m_CommunicationActivity_Timer.Enabled = false;
string szLocalIPAddress = GetLocalIPAddress_AsString(); // Get local IP address as a default value
txtIPAddress.Text = szLocalIPAddress; // Place local IP address in IP address field
txtPort.Text = "8000"; // Default port number
}
private void btnConnect_Click(object sender, EventArgs e)
{
// Connect the Socket with a remote endpoint
try
{
// Create the socket, for TCP use
m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ClientSocket.Blocking = true; // Socket operates in Blocking mode initially
}
catch // Handle any exceptions
{
Close_Socket_and_Exit();
}
try
{
// Get the IP address from the appropriate text box
String szIPAddress = txtIPAddress.Text;
System.Net.IPAddress DestinationIPAddress = System.Net.IPAddress.Parse(szIPAddress);
// Get the Port number from the appropriate text box
String szPort = txtPort.Text;
int iPort = System.Convert.ToInt16(szPort, 10);
// Combine Address and Port to create an Endpoint
m_remoteEndPoint = new System.Net.IPEndPoint(DestinationIPAddress, iPort);
m_ClientSocket.Connect(m_remoteEndPoint);
m_ClientSocket.Blocking = false; // Socket is now switched to Non-Blocking mode for send/ receive activities
txtLog.Text = "Connected";
m_CommunicationActivity_Timer.Start(); // Start the timer to perform periodic checking for received messages
}
catch // Catch all exceptions
{ // If an exception occurs, display an error message
txtLog.Text = "(Connect attempt failed)\nRetry Connect";
}
}
private void OnTimedEvent_PeriodicCommunicationActivityCheck(Object myObject, EventArgs myEventArgs)
{ // Periodic check whether a message has been received
try
{
EndPoint RemoteEndPoint = (EndPoint)m_remoteEndPoint;
byte[] ReceiveBuffer = new byte[1024];
int iReceiveByteCount;
iReceiveByteCount = m_ClientSocket.ReceiveFrom(ReceiveBuffer, ref RemoteEndPoint);
string szReceivedMessage;
if (0 < iReceiveByteCount)
{ // Copy the number of bytes received, from the message buffer to the text control
szReceivedMessage = Encoding.ASCII.GetString(ReceiveBuffer, 0, iReceiveByteCount);
txtResult.Text = szReceivedMessage;
}
}
catch // Silently handle any exceptions
{
}
}
private void Close_Socket_and_Exit()
{
try
{
m_ClientSocket.Shutdown(SocketShutdown.Both);
}
catch // Silently handle any exceptions
{
}
try
{
m_ClientSocket.Close();
}
catch // Silently handle any exceptions
{
}
this.Close();
}
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
String szData = "QuitConnection"; // Special code to signal 'close connection' to the server
// This ensures that the server is aware the Client wants to close the connection
// (TCP should otherwise automatically detect disconnection, but this approach ensures a clean disconnect)
byte[] byData = System.Text.Encoding.ASCII.GetBytes(szData);
m_ClientSocket.Send(byData, SocketFlags.None);
m_ClientSocket.Shutdown(SocketShutdown.Both);
m_ClientSocket.Close();
btnConnect.Text = "Connect";
txtResult.Text = "";
}
catch // Silently handle any exceptions
{
}
}
private string GetLocalIPAddress_AsString()
{
string szHost = Dns.GetHostName();
string szLocalIPaddress = "127.0.0.1"; // Default is local loopback address
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress IP in IPHost.AddressList)
{
if (IP.AddressFamily == AddressFamily.InterNetwork) // Match only the IPv4 address
{
szLocalIPaddress = IP.ToString();
break;
}
} return szLocalIPaddress;
}
}
}