⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpudpserver.cs

📁 WinChat was created in late 2000 by Spectre, DeMENted and Unique_T. You can connect to WinChat.Ne
💻 CS
📖 第 1 页 / 共 2 页
字号:
/* File        :  TcpUdpServer.cs
 * Namespace   :  ClientServer
 * Classes     :  TcpUdpServer
 */
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Timers;

namespace ClientServer
{
	/* Class			: TcpUdpServer
	 * Base Class		: TcpListener
	 * Functionality	: Handles all the server side functionalities including:
	 *                    1.  Creates a TcpListener to listen to incoming connection request;
	 *                    2.  Creates a UDP socket to handle all the call initiation messages like
	 *                        NOTIFY REQUEST and NOTIFY HANGUP REQUEST.
	 */

	public class TcpUdpServer : TcpListener
	{	

		private Socket udpNotifySocket;
		private Thread sampleTcpThread, udpNotifyThread;
		private System.Timers.Timer receiveNotifyTimer;
		private DateTime elapsedDateTime = DateTime.MinValue;
		
		public String dataReceivedTcp;
		public int tcpBytesReceived;
		public TcpListener tcpListener;
		public Socket tcpSocket;
		public IPEndPoint remoteIpEndPoint;

		public bool serverReceivedHangup = false;

		public delegate void NotificationHandler();
		public static event NotificationHandler peerNotify;
		public static event NotificationHandler peerHangup;

		public bool alreadyTalking = false;
		
		public TcpUdpServer() : base(ClientServerConstants.SAMPLETCPPORT)
		{
		}
		
		/* Function     : StartListen()
		 * Purpose      : This function will run as a thread to listen to the incoming
		 *                TCP connection.  
		 * Algorithm    : It first starts the TcpListener (similar to calling
		 *                Listen in the traditional Socket program).  It will then call
		 *                TcpListener.AcceptSocket() to "wait" for a client's connection.
		 *                After that, it follows the traditional way to call 
		 *                SetSocketOption(), and Receive().  After receiving the data (a byte 
		 *                array) from the client, the byte array will be converted to a String by
		 *                dataReceivedTcp = System.Text.Encoding.ASCII.GetString(received).  
		 *                "dataReceivedTcp" will then be used by the Windows Form application to
		 *                display onto the TextBox control.  When the client wants to close the 
		 *                connection, it will issue a "notifyLastMessage" to tell the server to
		 *                close the socket after receiving this message.  The while block would then 
		 *                return to TcpListener.AcceptSocket() to "wait" for another connection.
		 *                
		 */
		public void StartListen()
		{
			try 
			{
				this.Start();
				
				while (true)
				{
					//This runs as a thread to listen to the incoming connections.
					//The program will block on AcceptSocket() until a client connects.
					tcpSocket = this.AcceptSocket();

					while (true)
					{	
						try
						{
							tcpSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 7200);
						}
						catch (SocketException se)
						{
							MessageBox.Show("A Socket Exception has occurred!" + se.ToString(), "WinChat", 
								MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
						}

						if (tcpSocket.Connected)
						{
							Byte[] received = new Byte[ClientServerConstants.MESSAGESIZE];

							tcpBytesReceived = tcpSocket.Receive(received, received.Length, SocketFlags.None);
				
							dataReceivedTcp = System.Text.Encoding.ASCII.GetString(received);

							//notifyLastMessage is sent to the server when the peer wants to hangup.  The 
							//purpose of this last message is just to unblock the Receive call above.
							if (String.Compare(dataReceivedTcp, ClientServerConstants.notifyLastMessage) == 0)
							{
								//Close the Socket for this connection.
								tcpSocket.Close();

								if (serverReceivedHangup == true)
								{
									//This message only gets printed on the side that receives the
									//HANGUP REQUEST.
									MessageBox.Show("The remote side has disconnected the call!", "WinChat", 
										MessageBoxButtons.OK);

									serverReceivedHangup = false;
								}
								break;
							}
						}
					}
				}
			}
			catch (SocketException se)
			{				
				//ErrorCode 10004 corresponds to the SocketException: A blocking operation was interrupted by 
				//a call to WSACancelBlockingCall.
				if (se.ErrorCode != 10004)
				{
					MessageBox.Show("A Socket Exception has occurred!" + se.ToString(), "WinChat", 
						MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				}
			}
		}

		/* Function     : receiveNotify()
		 * Purpose      : This function will run as a thread to handle the incoming notifications
		 *                sent from the peer (e.g. NOTIFY REQUEST and NOTIFY HANGUP).  The 
		 *                notifications are handled by UDP connections because of their "come and
		 *                go" nature.
		 * Algorithm    : Since there is no UDP counterpart of TcpListener, I use the traditional
		 *                Socket programming here to handle UDP connections.  The following calls
		 *                are made to setup the UDP server: Socket(), Bind(), ReceiveFrom().  When
		 *                data (a byte array) is received, it will be converted to String by calling
		 *                dataNotifyReceivedUdp = System.Text.Encoding.ASCII.GetString(received).  
		 *                The received String will then determine what the server should do next:
		 *                1.  If the received String is "notifyRequest", the server will find out to 
		 *                    see if the application is in "alreadyTalking" mode.  If so, it won't
		 *                    accept this call request, and will return a message to let the remote 
		 *                    peer know that the local user is "already talking to someone
		 *                    else, please try again later."
		 *                    If the server is not in "alreadyTalking" mode, the server will pop up
		 *                    a MessageBox to ask the called user if he/she wants to accept the call.
		 *                    If the called user answers "Yes", this UDP thread will invoke the delegate
		 *                    peerNotify(), so that the Windows Form application can be notified of 
		 *                    the event, and take appropriate action (create a TcpClient to connect to
		 *                    the remote TcpListener).  If the called user answers "No", the UDP server 
		 *					  will simply return a negative notification to the calling user.
		 *                    It's noteworthy that a timer of 30 seconds will be started as soon as
		 *                    the "notifyRequest" is received.  If the called user does not answer the
		 *                    question within 30 seconds, the timer will expire and the called user will
		 *					  be notified that he has missed a call, when he/she answers the question
         *                    after 30 seconds.
		 *                2.  If the received String is "notifyHangupRequest", the UDP server will return
		 *                    a "notifyHangupAccept" to the calling user.  It will also invoke the
		 *                    delegate peerHangup() to notify the Windows Form application about the
		 *                    event, so that the Windows Form application will take the appropriate action
		 *                    (close the TcpClient).
		 *            
		 */
		public void receiveNotify()
		{			
			IPHostEntry localNotifyHostEntry;
		
			try
			{
				//Create an UDP socket.
				udpNotifySocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
				
				localNotifyHostEntry = Dns.GetHostByName(Dns.GetHostName());
			
				IPEndPoint localNotifyIpEndPoint = new IPEndPoint(localNotifyHostEntry.AddressList[0], 
														ClientServerConstants.UDPNOTIFYPORT);
			
				EndPoint localNotifyEndPoint = (localNotifyIpEndPoint);

				udpNotifySocket.Bind(localNotifyEndPoint);
				//			
				while (true)
				{
					Byte[] received = new Byte[ClientServerConstants.NOTIFYMESSAGESIZE];

					//This is just a dummy endpoint that will be replaced after the call to ReceiveFrom.
					//In the ReceiveFrom call later on, dummyIpEndPoint will be passed by ref.
					IPEndPoint dummyIpEndPoint = new IPEndPoint(localNotifyHostEntry.AddressList[0], 
													ClientServerConstants.UDPNOTIFYPORT);

					EndPoint remoteNotifyEP = (dummyIpEndPoint);

					int udpNotifyBytesReceived = udpNotifySocket.ReceiveFrom(received, ref remoteNotifyEP);

					String dataNotifyReceivedUdp = System.Text.Encoding.ASCII.GetString(received);
							
					//I could have used a switch() statement in the following code.  however, for some
					//reason the call to dataNotifyReceivedUdp.Equals(ClientServerConstants.notifyRequest)
					//always returns false.  I will investigate this problem further.
					if (String.Compare(dataNotifyReceivedUdp, ClientServerConstants.notifyRequest) == 0)
					{	
						if (alreadyTalking == true)
						{
							Byte[] returningByte = System.Text.Encoding.ASCII.GetBytes(
								(ClientServerConstants.notifyAlreadyTalking).ToCharArray());
								
							udpNotifySocket.SendTo(returningByte, remoteNotifyEP);
						}
						else
						{
							//The WinChatForm needs this remoteIpEndPoint to create a connection
							//in the reverse direction.
							remoteIpEndPoint = (IPEndPoint)remoteNotifyEP;

							DialogResult dialogResult;
						
							//This Notify Timer is started to make sure the called user can answer
							//this call within 30 seconds, so that the calling user does not have

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -