본문 바로가기
C++/예제

[C++][MFC] UDP 통신 (1) 채팅 프로그램 1대1 예제

by 부먹짱 2022. 9. 19.
반응형

 

UDP 통신으로 서버, 클라이언트의 구분이 없는 1대1 채팅 프로그램을 구현하였다.

 

최종 결과 화면

 

UDP_ServerDlg.h

 

public:
	CListBox m_msg_list;
	CEdit msgEdit;
	CEdit rIpEdit;
	CEdit rPortEdit;
	CEdit mPortEdit;

	void InsertMsg(CString str);
	afx_msg void ConnectBtnClicked();
	afx_msg void SendBtnClicked();
	static UINT RecvFunc(LPVOID pParam);

private:
	SOCKET remote_socket;
	SOCKET my_socket;
	SOCKADDR_IN my_addr;
	SOCKADDR_IN remote_addr;

 

UDP_ServerDlg.cpp

 

// 연결 버튼 클릭 함수
void CUDPServerDlg::ConnectBtnClicked()
{
	UINT mPort;
	CString strPort;
	mPortEdit.GetWindowText(strPort); // 사용자 입력 포트
	mPort = _tstoi(strPort);
	
	// 자신 ip 가져오기 
	char myaddr[20] = "";
	gethostname(myaddr, sizeof(myaddr));
	PHOSTENT hostInfo = gethostbyname(myaddr);
	SOCKADDR_IN addr;
	CArray<sockaddr_in, sockaddr_in& > ipArray;
	CString msgIp("");
	if (hostInfo) {
		for (int i = 0; hostInfo->h_addr_list[i] != NULL; i++) {
			memcpy(&addr.sin_addr, hostInfo->h_addr_list[i], hostInfo->h_length);
			ipArray.Add(addr);
		}
	} 

	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(mPort);
	my_addr.sin_addr.s_addr = ipArray.GetAt(0).sin_addr.s_addr;
	// my_addr.sin_addr.s_add = htonl(INADDR_ANY) : 127.0.0.1로 설정

	UINT rPort;
	CString strPort2;
	rPortEdit.GetWindowText(strPort2); // 사용자 입력 상대 포트
	rPort = _tstoi(strPort2);

	TCHAR rIp[20];
	rIpEdit.GetWindowTextA(rIp, 20); // 사용자 입력 상대 ip

	remote_addr.sin_family = AF_INET;
	remote_addr.sin_port = htons(rPort);
	remote_addr.sin_addr.s_addr = inet_addr(rIp);

	my_socket = socket(PF_INET, SOCK_DGRAM, 0); // 자신 소켓 생성
	if (my_socket == INVALID_SOCKET) InsertMsg("my socket error");

	if (bind(my_socket, (SOCKADDR*)&my_addr, sizeof(my_addr)) == -1) // 소켓 bind()
	{
		InsertMsg(_T("bind error"));
		return;
	}

	remote_socket = socket(PF_INET, SOCK_DGRAM, 0); // 상대 소켓 생성
	if (remote_socket == INVALID_SOCKET)
	{
		InsertMsg("remote socket error");
		return;
	}

	InsertMsg(_T("Address Setting Complete"));

	AfxBeginThread(RecvFunc, this); // 수신 스레드 시작
}

 

반응형

 

// 수신 스레드
UINT CUDPServerDlg::RecvFunc(LPVOID pParam) {

	CUDPServerDlg* pDlg = (CUDPServerDlg*)pParam;

	while (1) 
	{
		char temp[1024] = "";
		int strlen;

		// 메시지 수신, 수신한 메시지 길이 반환
		strlen = recvfrom(pDlg->my_socket, temp, sizeof(temp), 0, NULL, NULL);
		if (strlen == -1) // 오류
		{
			pDlg->InsertMsg("read error");
			break;
		}
		else // 메시지 정상 수신
		{
			CString str = (LPSTR)temp;
			pDlg->InsertMsg(str); // 메시지 ListBox에 추가
		}
	}
	closesocket(pDlg->my_socket);
	return 0;
}

 

// 전송 버튼 클릭 함수
void CUDPServerDlg::SendBtnClicked()
{
	CString msg, str;
	msgEdit.GetWindowText(msg);
	InsertMsg("ME : " + msg); // 자신이 보낸 메시지 ListBox 추가

	// 메시지 보낼 때 User (ip : port)로 보이도록 메시지 가공
	str.Format(_T("User (%s : %d) : "), inet_ntoa(my_addr.sin_addr), ntohs(my_addr.sin_port));
	msg = str + msg;

	int len = msg.GetLength();
	char* message = new char[len + 10];
	strcpy(message, msg.GetBuffer(0));

	// 상대에게 메시지 전송
	if (sendto(remote_socket, message, 1024, 0, (SOCKADDR*)&remote_addr, sizeof(remote_addr)) == -1)
	{
		InsertMsg("send error");
	}
	else 
	{
		msgEdit.SetWindowTextA("");
	}
}

 

// 메시지 ListBox 추가 함수
void CUDPServerDlg::InsertMsg(CString str)
{
	m_msg_list.InsertString(-1, str);
	m_msg_list.SetTopIndex(m_msg_list.GetCount() - 1);
}

 

결과 화면

 

 

UDP_ServerDlg.h
0.00MB
UDP_ServerDlg.cpp
0.01MB

 

반응형

댓글