udp thread를 이용한 간단한 채팅에서 recvfrom이 안됩니다.
안녕하세요
제가 만들고 있는 프로그램은 송수신을 동시에 하는 간단한 채팅프로그램입니다.
tcp로는 작동을 잘 하는데 udp로 바꾸니 클라이언트에서 보낸 메세지를 서버가 받아서
다시 클라이언트 화면에 메세지를 출력시켜주는 부분이 동작하지 않습니다.
recvfrom과 thread의 문제인지, 소켓 설정을 잘못한 것인지 한참을 고민하고 참고될 자료도
찾아보았지만 해결하지 못해서 여기에 질문을 올립니다.
//서버
#include
#include
#include
#include
#include
#define BUFSIZE 100
DWORD WINAPI ClientConn(void *arg);
void SendMSG(char* message, int len);
void ErrorHandling(char *message);
int clntNumber =0;
SOCKET clntSocks[10];
HANDLE hMutex;
SOCKADDR_IN clntAddr;
SOCKET servSock;
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKADDR_IN servAddr;
HANDLE hThread;
DWORD dwThreadID;
int strLen=0;
char message[BUFSIZE]={0,};
int clntAddr_size;
int i;
if(argc!=2) {
printf("Usage : %s \n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0) /* 윈도우 소켓 버전을 알리고 라이브리러 초기화 작업을 한다.*/
ErrorHandling ("WSAStartup() error!");
hMutex = CreateMutex(NULL, FALSE, NULL); /* 공유 자원을 위한 뮤텍스 생성 */
if(hMutex==NULL)
ErrorHandling ("CreateMutex() error");
servSock=socket(PF_INET, SOCK_DGRAM,0); /* 서버 소켓 생성 */
if(servSock==INVALID_SOCKET)
ErrorHandling ("socket() error");
memset(&servAddr, 0, sizeof(servAddr)); /* 주소 체계를 구조체 형태로 정의한다 */
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=htonl(INADDR_ANY);
servAddr.sin_port=htons(atoi(argv[1]));
if(bind(servSock, (SOCKADDR*) &servAddr, sizeof(servAddr))==SOCKET_ERROR) /* 소켓에 구조체 주소 체계를 할당한다 */
ErrorHandling("bind() error");
while(1){
clntAddr_size = sizeof(clntAddr);
//WaitForSingleObject(hMutex, INFINITE); // 다른 스레드가 종료되기를 기다리면서 대기하다가 다른 스레드가 종료되면 못다한 일을 처리하도록 하는 함수
clntSocks[clntNumber++]=servSock;
//ReleaseMutex(hMutex);
/* 멀티 스레드를 위해 beginthreadex를 이용해 스레드를 생성한다 */
//hThread = (HANDLE)_beginthreadex(NULL, 0, ClientConn,(void*)servSock, 0, (unsigned *)&dwThreadID);
for(i=0; i
{
strLen=recvfrom(clntSocks[i], message, BUFSIZE, 0, (SOCKADDR*) &clntAddr,&clntAddr_size);
//printf("recv %s",message);
SendMSG(message, strLen);
}
if(!strcmp(message, "q\n")) { // q를 누르면 종료되게 한다.
closesocket(servSock);
exit(0);
}
//if(hThread == 0)
//ErrorHandling("쓰레드 생성 오류");
}
WSACleanup();
closesocket(servSock);
return 0;
}
//
//DWORD WINAPI ClientConn(void *arg) // 스레드로 실행될 함수의 스레드 핸들을 생성
//{
//
// SOCKET clntSock = (SOCKET)arg; // 인자값을 소켓으로 케스팅한다.
// int strLen=0;
// char message[BUFSIZE];
// int i;
//
// while((strLen=recvfrom(clntSock, message, BUFSIZE, 0, (SOCKADDR*) &clntAddr,&clntAddr_size)) != 0) //클라이언트가 보낸 메세지를 버퍼에 담는다.
// SendMSG(message, strLen); //메세지를 읽어 모든 클라이언트에 전송한다.
//
// WaitForSingleObject(hMutex, INFINITE); //뮤텍스를 얻어 클라이언트의 접속 종료처리를 한다.
//
// for(i=0; i
// if(clntSock == clntSocks[i]) {
// for(; i
// clntSocks[i] = clntSocks[i+1];
// break;
// }
// }
//
// clntNumber--;
// ReleaseMutex(hMutex); // 뮤텍스를 해제한다.
// closesocket(clntSock); // 해당 소켓을 닫는다.
//
// return 0;
//}
void SendMSG(char* message, int len)
{
int i;
WaitForSingleObject(hMutex, INFINITE);
for(i=0; i
sendto(clntSocks[i],message,len,0,(SOCKADDR*) &clntAddr,sizeof(clntAddr));
//printf("send %s",message);
ReleaseMutex(hMutex);
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
*********************클라이언트
#include
#include
#include
#include
#include
#define BUFSIZE 100
#define NAMESIZE 20
DWORD WINAPI SendMSG(void *arg);
DWORD WINAPI RecvMSG(void *arg);
void ErrorHandling(char *message);
char name[NAMESIZE]="[Default]";
char message[BUFSIZE];
SOCKADDR_IN servAddr;
int servAddr_size;
SOCKET sock;
int main(int argc, char **argv)
{
WSADATA wsaData;
//SOCKET sock;
HANDLE hThread1,hThread2;
DWORD dwThreadID1,dwThreadID2;
if(argc!=4) {
printf("Usage : %s \n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0)
ErrorHandling ("WSAStartup() error!");
sprintf(name, "[%s]", argv[3]);
sock=socket(PF_INET, SOCK_DGRAM,0); /* 소켓 생성 */
if(sock==INVALID_SOCKET)
ErrorHandling ("socket() error");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=inet_addr(argv[1]);
servAddr.sin_port=htons(atoi(argv[2]));
connect(sock,(SOCKADDR*)&servAddr,sizeof(servAddr));
servAddr_size = sizeof(servAddr);
hThread1 = (HANDLE)_beginthreadex(NULL, 0, SendMSG, (void*)sock, 0, (unsigned *)&dwThreadID1);
//연결된 소켓 디스크립터를 매개변수로 송/수신 스레드를 생성한다.
hThread2 = (HANDLE)_beginthreadex(NULL, 0, RecvMSG, (void*)sock, 0, (unsigned *)&dwThreadID2);
if(hThread1==0 || hThread2==0)
ErrorHandling("쓰레드 생성 오류");
WaitForSingleObject(hThread1, INFINITE); //스레드가 종료될때까지 메인함수의 종료를 막는다.
WaitForSingleObject(hThread2, INFINITE);
closesocket(sock);
return 0;
}
DWORD WINAPI SendMSG(void *arg) //메세지 전송 스레드 함수
{
//SOCKET sock = (SOCKET)arg; //소켓형으로 케스팅
char nameMessage[NAMESIZE + BUFSIZE];
while(1) {
fgets(message, BUFSIZE, stdin); //키보드로 부터 메세지 입력
sprintf(nameMessage,"%s %s", name, message); //이름과 메세지를 출력
if(!strcmp(message, "q\n")) { // q를 누르면 종료되게 한다.
closesocket(sock);
exit(0);
}
//sendto(sock, nameMessage, strlen(nameMessage), 0,(SOCKADDR*)&servAddr,sizeof(servAddr)); //메세지 전송
send(sock,nameMessage,strlen(nameMessage), 0);
}
}
DWORD WINAPI RecvMSG(void *arg) //메세지 수신 스레드
{
//SOCKET sock = (SOCKET)arg; //소켓형으로 케스팅
char nameMessage[NAMESIZE + BUFSIZE];
int strLen;
while(1) {
//strLen= recvfrom(sock, nameMessage, NAMESIZE+BUFSIZE-1,0,(SOCKADDR*)&servAddr,&servAddr_size); //서버로부터 메세지를 받아온다.
strLen= recv(sock, nameMessage, NAMESIZE+BUFSIZE-1,0);
//printf("client recv : %s",nameMessage);
//if(strLen==-1) return 1;
nameMessage[strLen]='\0';
fputs(nameMessage, stdout); //받아온 메세지를 출력한다.
}
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
서버쪽 보내고 받는 부분에서 printf로 무엇을 보내고 받나 실험해보니 보내고 받는건 동작하는데
클라이언트의 recvfrom이 먹통인것 같습니다. 조언 부탁드립니다.
송신 수신을 동시에 라는 조건 때문에 thread를 썻는데 다른 간단한 방법이 있는지도 궁금합니다.
댓글 달기