tcp/ip c++ 即时通讯聊天室(三)服务端实现

服务端代码实现:(大佬请飘过)
一下三个文件分别对应第一期的三个头文件:

  1. Server_LAN 负责程序的初始化
  2. ServerDlg_LAN 负责使用MFC创建聊天室的对话框和处理事件,并显示发送来的数据
  3. ServerManager_LAN 负责通信和创建进程

具体代码原理看注释,这里小编为了方便将注释用英文编写,部分采用中文,若有看不懂请在评论区留言或者有道翻译

写码不易,关注收藏一下呗,谢谢各位!!!

第四篇文章(内网穿透实现公网通信)
https://blog.csdn.net/qq_42662283/article/details/106621012

Server_LAN.cpp

#include "stdafx.h"
#include "Server_LAN.h"
#include "ServerDlg_LAN.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CServerApp

BEGIN_MESSAGE_MAP(CServerApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CServerApp construction

CServerApp::CServerApp()
{
     
	// support Restart Manager
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}


// The one and only CServerApp object

CServerApp theApp;


// CServerApp initialization

BOOL CServerApp::InitInstance()
{
     
	// InitCommonControlsEx() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// Set this to include all the common control classes you want to use
	// in your application.
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	AfxEnableControlContainer();

	// Create the shell manager, in case the dialog contains
	// any shell tree view or shell list view controls.
	CShellManager *pShellManager = new CShellManager;

	// Standard initialization
	
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	CServerDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
     
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
     
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}

	// Delete the shell manager created above.
	if (pShellManager != NULL)
	{
     
		delete pShellManager;
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}

void CServerApp::OnServerAction(string sValue)
{
     
	CString strLine;
    // add CR/LF to text
    strLine.Format(_T("\r\n%s"), sValue);
	
	//dlg.m_buffer = strLine;
	//dlg.DoModal();
}

ServerDlg_LAN.cpp

// ServerDlg.cpp : implementation file
//
#include "ServerManager_LAN.h"
#include "stdafx.h"
#include "Server_LAN.h"
#include 
#include "ServerDlg_LAN.h"
#include "afxdialogex.h"
//#include 

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include 
#include 



// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
     
public:
	CAboutDlg();

// Dialog Data
	enum {
      IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
     
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
     
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CServerDlg dialog
CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/): CDialogEx(CServerDlg::IDD, pParent),m_pServer(NULL)
{
     
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_buffer = _T("This is a Magic TCP chat room!!!\r\n");
	cTh = NULL;
}

void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
     
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT2, m_buffer);
	DDX_Control(pDX, IDC_EDIT2, m_Textbox);
	DDX_Control(pDX, IDC_EDIT1, m_Portbox);
}

BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDCANCEL, &CServerDlg::OnBnClickedCancel)
	ON_BN_CLICKED(IDOK, &CServerDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BT_START, &CServerDlg::OnClickedBtStart)
    ON_BN_CLICKED(IDC_BT_STOP, &CServerDlg::OnClickedBtStop)
	ON_BN_CLICKED(IDC_BT_CLEAR, &CServerDlg::OnClickedBtClear)
END_MESSAGE_MAP()


// CServerDlg message handlers

BOOL CServerDlg::OnInitDialog()
{
     
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.
	
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
     
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
     
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
     
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
     
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
     
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CServerDlg::OnPaint()
{
     
	if (IsIconic())
	{
     
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
     
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CServerDlg::OnQueryDragIcon()
{
     
	return static_cast<HCURSOR>(m_hIcon);
}

void CServerDlg::OnBnClickedCancel()
{
     
	// TODO: Add your control notification handler code here
	CDialogEx::OnCancel();
}

void CServerDlg::OnBnClickedOk()
{
     
	// TODO: Add your control notification handler code here
	//CDialogEx::OnOK();
	OnClickedBtStart();
}

void CServerDlg::OnClickedBtStart()
{
     
	if (!cTh)
	{
     
		//开启新的线程
		cTh = AfxBeginThread(StaticThreadFunc, this);
		//cTh->m_bAutoDelete = FALSE;
		m_Thread_handle = cTh->m_hThread;//返回该线程的Handle
	}
	else
	{
     
		ShowServerInfo("There has been a serve running......\r\n");
	}
}

void CServerDlg::OnClickedBtStop()
{
     
	if (m_Thread_handle != NULL)
	{
     
		CloseHandle(m_Thread_handle);
	}
	cTh = NULL;
	if (m_pServer != NULL) 
	{
     
		m_pServer->ClearServer();
		m_pServer = NULL;
		ShowServerInfo("Stop serve successful\r\n");
	}
	else
	{
     
		ShowServerInfo("The serve is not running......\r\n");
	}
}

void CServerDlg::ShowServerInfo(string sValue)
{
     
	CString strLine(sValue.c_str());
	// add CR/LF to text
	//MessageBox(sValue.c_str());
	AppendTextToEditCtrl(m_Textbox, strLine);
	//DoModal();
	//UpdateData(TRUE);
}

void CServerDlg::AppendTextToEditCtrl(CEdit& edit, LPCTSTR pszText)
{
     
   // get the initial text length
   int nLength = edit.GetWindowTextLength();
   // put the selection at the end of text
   edit.SetSel(nLength, nLength);
   // replace the selection
   edit.ReplaceSel(pszText);
}

UINT __cdecl CServerDlg::StaticThreadFunc(LPVOID pParam)
{
     
	CServerDlg *pYourClass = reinterpret_cast<CServerDlg*>(pParam);
    UINT retCode = pYourClass->ThreadFunc();

    return retCode;
}

UINT CServerDlg::ThreadFunc()
{
      
    // Do your thing, this thread now has access to all the classes member variables
	CString txtname; 
	GetDlgItemText(IDC_EDIT1, txtname);
	int iPort = _wtoi( txtname.GetString() );

	if(iPort == 0)
	{
     
		return -1;
	}
	m_pServer = new ServerManager(this);
	m_pServer->StartListening(iPort);
	return 0;
}

void CServerDlg::OnClickedBtClear()
{
     
	// TODO: 在此添加控件通知处理程序代码
	CWnd* pWnd = GetDlgItem(IDC_EDIT2);
	pWnd->SetWindowText(_T("This is a Magic TCP chat room!!!\r\n"));
}

ServerManager_LAN.cpp


#include   
#include   
#include
#include "StdAfx.h"
#include "ServerManager_LAN.h"
#include "Server_LAN.h"
#include "ServerDlg_LAN.h"
#include 
#include 
#include 

static SOCKET sArray[100];
static int iCount;
ServerManager::ServerManager(CServerDlg* dialog)
{
     
	m_pDialog = dialog;
}

ServerManager::~ServerManager()
{
     
	
	closesocket(s);
    WSACleanup();
}

void ServerManager::ClearServer()
{
     
	closesocket(s);
    WSACleanup();//terminates use of the Ws2_32.dll

	/*
	for(int i=1;i<=iCount;++i)
	{
		DWORD dwCode;  
        GetExitCodeThread(cpTh[i]->m_hThread, &dwCode);  
        delete cpTh[i];
		//CloseHandle(m_Thread_handle[i]);
	}*/
}

void ServerManager::StartListening(int iPort)
{
     
	iCount=0;
	printf("\nInitialising Winsock...");
	//WASStartup: initiates use of Ws2_32.dll by a process
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
     
        printf("Failed. Error Code : %d", WSAGetLastError());
        return;
    }
    
    printf("Initialised.\r\n");
    
    //Create a socket(AF_INET: internet work, SOCK_STREAM: Use TCP protocol)
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
     
        printf("Could not create socket : %d" , WSAGetLastError());
		m_pDialog->ShowServerInfo("Could not create socket");
    }
 
    printf("Socket created.\r\n");
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( iPort );
     
    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
     
        printf("Bind failed with error code : %d" , WSAGetLastError());
		m_pDialog->ShowServerInfo("Bind failed with error code");
        exit(EXIT_FAILURE);
    }
     
    puts("Bind done");
 
    //Listen to incoming connections, maximum connection 100
    listen(s , 100);
	 char *message;
	 puts("Waiting for incoming connections...");
     m_pDialog->ShowServerInfo("Waiting for incoming connections...\r\n");
     c = sizeof(struct sockaddr_in);
     
    while( (new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET )
    {
     
        puts("Connection accepted");
       // m_pDialog->ShowServerInfo("Connection accepted\n");
        //Reply to the client
		socklen_t len;
		struct sockaddr_storage addr;
		char ipstr[INET6_ADDRSTRLEN];
		int port;

		len = sizeof addr;
		//retrieves the name of the peer to which a socket is connected
		getpeername(new_socket, (struct sockaddr*)&addr, &len);

		// deal with IPv4:
		if (addr.ss_family == AF_INET) {
     
			struct sockaddr_in *s = (struct sockaddr_in *)&addr;
			port = ntohs(s->sin_port);
			//converts an (Ipv4) Internet network address into a string in Internet standard dotted format
			inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
		}

		printf("Peer IP address: %s\r\n", ipstr);
		m_pDialog->ShowServerInfo("Connected Peer IP address: " + string(ipstr) + "\r\n");
		CWinThread *cTh = AfxBeginThread(DataThreadFunc, (LPVOID)new_socket);
		++iCount;
		//m_Thread_handle[++iCount] = cTh->m_hThread;
		//cpTh[iCount] = cTh;
		sArray[iCount] = new_socket;//store the new connection
		//message = "Hello Client , I have received your connection.\n";
        //send(new_socket , message , strlen(message) , 0);

		//SetStaticVariable(iTempCount, new_socket);
    }
     
    if (new_socket == INVALID_SOCKET)
    {
     
        printf("accept failed with error code : %d" , WSAGetLastError());
        return;
    }
}

UINT __cdecl ServerManager::DataThreadFunc(LPVOID pParam)
{
     
	SOCKET pYourSocket = reinterpret_cast<SOCKET>(pParam);
    //UINT retCode = pYourClass->ThreadFunc();
	//SendReceiveData(pYourClass);


	char *message;
	message = "Welcome to Magic TCP chat room.\r\n";
    send(pYourSocket , message , strlen(message) , 0);//send the message to a specific connected socket
	const int REC_BUFFERSIZE = 1024;
	char server_reply[REC_BUFFERSIZE + 1];
    int recv_size;

	while((recv_size = recv(pYourSocket , server_reply , REC_BUFFERSIZE , 0)) != SOCKET_ERROR)
	{
     
		server_reply[recv_size] = '\0';//the end of a string
		//m_pDialog->ShowServerInfo("Message Received: "+ string(server_reply));
		for(int i = 1;i <= iCount; i++)
		{
     
			//将收到的消息转发给每一个连接的客户端
			if(sArray[i] != pYourSocket)//没必要转发给发消息的人
			{
     
				if (send(sArray[i], server_reply, recv_size, 0) == SOCKET_ERROR)
				{
     
					puts("Send failed");
				}
				printf(server_reply);
				printf("\n");
			}
		}
		send(pYourSocket, "READY!", 6, 0);//发送确认回信
	}
    return 0;
}

UINT ServerManager::SendReceiveData(SOCKET cSocket)
{
     
	return 0;
}

void ServerManager::SetStaticVariable(int iC, SOCKET cS)
{
     
	iCount = iC;
	sArray[iCount] = cS;
}

第四篇文章(内网穿透实现公网通信)
https://blog.csdn.net/qq_42662283/article/details/106621012

你可能感兴趣的:(tcp/ip,c++,即使通讯聊天室,socket,mfc,c++,多人聊天室)