udp thread를 이용한 간단한 채팅에서 recvfrom이 안됩니다.

violetoov의 이미지

안녕하세요

제가 만들고 있는 프로그램은 송수신을 동시에 하는 간단한 채팅프로그램입니다.

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를 썻는데 다른 간단한 방법이 있는지도 궁금합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.