C++ 소켓에서 고통 받고 있습니다.ㅠㅠㅠ 도와주실 분 있으신가요

익명 사용자의 이미지

선 질문입니다.

1. 서버/클라이언트 구조를 만들려고 합니다. 만약에 둘 중 하나에서 Send를 했 다른 하나에서 recv를 걸었으나 2개 이상의 Send Recv 구조에선 각 Send하고 Recv가 어디에 걸리는지 모르겠습니다...ㅠㅠ

예를 들어

Send(1)

Recv(1)

Send(2)

Recv(2)

라면 1은 1에만 걸리고 2는 2에만 걸리는 건가요?

각 서버와 노드에서 코드를 읽는 속도가 다를 것 같은데, 그렇게 되면 한쪽에서 먼저 Send(2)까지 읽어버리고 쏴주면 Recv(1)은 Send(2)를 받는게 아닌가 해서요.. ㅠㅠ

2. 아래 코드에서 중간 두 부분부터 먹통이 되길래 계속 자료형 바꿔가면서 테스트를 해보았는데... (6시간넘게..)
아래 printf를 붙여서 어디서 부터 먹통이 되는지 체크하는 방법은 터득했는데.. 정작 문제가 해결이 안 됩니다.ㅠㅠ

----------------------------------------------------------
printf("\n1");

ret = send(*(SOCKET*)ns, welcome, MAX_BUFFER, 0);

printf("\n2");
--------------------------------------------------------

이 부분에서 welcome이 서버에서 제대로 송신은 된 것 같은데, 클라이언트 단에서는 출력이 안 됩니다.

--------------------------------------------------------
while (1);
{
printf("\n3");

recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

printf("클라이언트의 ID는 %s 이다.)\n", messageBuffer);
WaitForSingleObject(hMutex, INFINITE);//뮤텍스 실행
strcpy(IDlist[IDcount], messageBuffer);
printf("ID는 %s", IDlist[IDcount]);
IDcount++;
ReleaseMutex(hMutex);//뮤텍스 중지

printf("\n4");

memset(&messageBuffer, 0, sizeof(messageBuffer));
_itoa_s(IDcount, messageBuffer, 10);
send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

printf("\n5");
--------------------------------------------------------

이 부분은 아예 진입을 못해서 goto문으로 while문 안으로 넣어줘도 애가 움직일 생각을 안 합니다.ㅠㅠ 1,2 까지는 출력이 되는데 3부터는 아예 됩니다...

같은 문제로 2일째 고심중입니다.. 고수님들의 도움 부탁드립니다.

----서버 코드

#include "stdafx.h"
#include
#include
#include
#include
#include

#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable:4996)

#define MAX_BUFFER 1024
#define SERVER_PORT 9001
#define Max_socket 5


SOCKET Clientlist[Max_socket]; //최대 5개까지
void makeThread(void *data);
int clientCount;

char welcome_ok[] = "접속을 환영한다.";
char IDlist[Max_socket][MAX_BUFFER];


int client_num;
int addrLen;
int IDcount = 0;
int recv_id[];
int clientSocket[MAX_BUFFER];

int i, j;

HANDLE hMutex;//뮤텍스

void makeThread(void *ns)
{

WaitForSingleObject(hMutex, INFINITE);
clientCount++;
client_num++;
printf("(슬롯 %d개 남음)\n", Max_socket - clientCount); // 갯수로 판단

ReleaseMutex(hMutex);
// 5-1. 데이터 읽기


char welcome[100] = { 0};
char messageBuffer[MAX_BUFFER] = { 0 };

double num1 = 0, num2 = 0;
double result = 0;
int ret;

printf("\n1");

ret = send(*(SOCKET*)ns, welcome, MAX_BUFFER, 0);

printf("\n2");

while (1);
{
printf("\n3");

recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

printf("클라이언트의 ID는 %s 이다.)\n", messageBuffer);
WaitForSingleObject(hMutex, INFINITE);//뮤텍스 실행
strcpy(IDlist[IDcount], messageBuffer);
printf("ID는 %s", IDlist[IDcount]);
IDcount++;
ReleaseMutex(hMutex);//뮤텍스 중지

printf("\n4");

memset(&messageBuffer, 0, sizeof(messageBuffer));
_itoa_s(IDcount, messageBuffer, 10);
send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

printf("\n5");

for (i = 0; i < Max_socket; i++)
{
memset(&messageBuffer, 0, sizeof(messageBuffer));
strcpy(messageBuffer, IDlist[i]);
send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

}

printf("\n5");

}

// 5-2.사칙연산, 종료
while (1)
{
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

if ((messageBuffer[0] == '+' || messageBuffer[0] == '-' || messageBuffer[0] == '/' || messageBuffer[0] == '*' || messageBuffer[0] == 'q') != 1)

{
//printf("바르게 입력바랍니다.\n");

memset(&messageBuffer, 0, sizeof(messageBuffer));
strcpy(messageBuffer, "incorrect command");
send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
continue;
}

if (messageBuffer[0] == '+')

{
printf("뎃섬을 하는군\n ");
memset(&messageBuffer, 0, sizeof(messageBuffer)); //숫자 1 받음
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num1 = atof(messageBuffer);
printf("숫자1은 %f이다\n", num1); // 숫자로 변환

memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num2 = atof(messageBuffer);
printf("숫자2은 %f 이다\n", num2); // 숫자로 변환

result = num1 + num2;

memset(&messageBuffer, 0, sizeof(messageBuffer));
sprintf(messageBuffer, "%f", result);

send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
}

if (messageBuffer[0] == '-')
{
printf("뺄셈을 하는군\n");
memset(&messageBuffer, 0, sizeof(messageBuffer)); //숫자 1 받음
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num1 = atof(messageBuffer);
printf("숫자1은 %f이다\n", num1); // 숫자로 변환

memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num2 = atof(messageBuffer);
printf("숫자2은 %f 이다\n", num2); // 숫자로 변환

result = num1 - num2;
memset(&messageBuffer, 0, sizeof(messageBuffer));
sprintf(messageBuffer, "%f", result);

send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

}

if (messageBuffer[0] == '*')
{
printf("곱셈\n");
memset(&messageBuffer, 0, sizeof(messageBuffer)); //숫자 1 받음
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num1 = atof(messageBuffer);
printf("숫자1은 %f이다\n", num1); // 숫자로 변환

memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num2 = atof(messageBuffer);
printf("숫자2은 %f 이다\n", num2); // 숫자로 변환

result = num1 * num2;

memset(&messageBuffer, 0, sizeof(messageBuffer));
sprintf(messageBuffer, "%f", result);

send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
}

if (messageBuffer[0] == '/')
{
printf("나눗셈\n");
memset(&messageBuffer, 0, sizeof(messageBuffer)); //숫자 1 받음
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num1 = atof(messageBuffer);
printf("숫자1은 %f이다\n", num1); // 숫자로 변환

memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);
num2 = atof(messageBuffer);
printf("숫자2은 %f 이다\n", num2); // 숫자로 변환

result = num1 / num2;

memset(&messageBuffer, 0, sizeof(messageBuffer));
sprintf(messageBuffer, "%f", result);

send(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

}

if (messageBuffer[0] == 'q') //사칙연산 나가기
{
memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(*(SOCKET*)ns, messageBuffer, MAX_BUFFER, 0);

WaitForSingleObject(hMutex, INFINITE);//뮤텍스 실행
for (i = 0; i < Max_socket; i++) //배열의 갯수만큼
{
if (IDlist[i][MAX_BUFFER] == messageBuffer[0]) //만약 현재 clientSock값이 배열의 값과 같다면

{
IDlist[i][MAX_BUFFER] = '0';
break;

}
}

for (i = 0; i = Max_socket; i++)
{
if (IDlist[i][MAX_BUFFER] = '0')
j = i;
}

for (i = j; i = Max_socket; i++)
{
IDlist[i][MAX_BUFFER] = IDlist[i + 1][MAX_BUFFER];
}

clientCount--;//클라이언트 개수 하나 감소
IDcount--;
printf("클라이언트 해제\n슬롯 %d개 남음\n", Max_socket - clientCount);

ReleaseMutex(hMutex);//뮤텍스 중지

break;
}

printf("나왔다");

}

closesocket(*(SOCKET*)ns); //연결된 클라이언트 정렬및 재정비하기.
printf("끝");

}

int main(void)
{
hMutex = CreateMutex(NULL, FALSE, NULL);

WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("Error - Can not load 'winsock.dll' file\n");
return -1;
}

// 1. 소켓생성

SOCKADDR_IN serverAddr, clientAddr;

SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket == INVALID_SOCKET)
{
printf("Error - Invalid socket\n");
return -1;
}
printf("socket Created\n\n");

// 서버정보 객체설정

serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

// 2. 소켓설정
if (bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
printf("Error - Fail bind\n");
closesocket(listenSocket);
// Winsock End
WSACleanup();
return -1;
}

printf("binding success...\n\n");

// 3. 수신대기열생성
if (listen(listenSocket, 5) == SOCKET_ERROR)
{
printf("Error - Fail listen\n");
closesocket(listenSocket);

WSACleanup();
return -1;
}
printf("on listening...\n\n");

// 연결대기 정보변수 선언

addrLen = sizeof(clientAddr);

// thread Handle 선언

while (1)
{
// 4. 연결대기 클라이언트소켓주소 배열에 저장
clientSocket[client_num] = accept(listenSocket, (struct sockaddr *)&clientAddr, &addrLen);

_beginthread(makeThread, 0, &clientSocket[client_num]);

printf("클라이언트 %s:%d 에서 접속", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));



}

// 6-2. 리슨 소켓종료
closesocket(listenSocket);
WSACleanup();

getchar();
getchar();

return 0;

}

클라이언트 코드

#include "stdafx.h"
#include
#include
#include
#include
#include

#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable:4996)

#define MAX_BUFFER 1024
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9001

void recv_thread(void* pData);
int count;
int listenSocket;
int ret;

char self_id[MAX_BUFFER];

int i, bufferLen;

int main(void)
{
// Winsock Start - winsock.dll 로드

WSADATA WSAData;
char messageBuffer[MAX_BUFFER];

if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("Error - Can not load 'winsock.dll' file\n");
return -1;
}

// 1. 소켓생성
SOCKADDR_IN serverAddr;

listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (listenSocket == INVALID_SOCKET)
{
printf("Error - Invalid socket\n");
closesocket(listenSocket);
WSACleanup();
return -1;
}

// 서버정보 객체설정


serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
serverAddr.sin_port = htons(SERVER_PORT);

// 2. 연결요청
if (connect(listenSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
printf("Error - Fail to connect\n");
// 4. 소켓종료
closesocket(listenSocket);
// Winsock End
WSACleanup();
return -1;
}

printf("connect success\n\n");
ret = recv(listenSocket, messageBuffer, MAX_BUFFER, 0);
printf("%s", messageBuffer);

printf("Server Connected\n* 너의 ID가 무엇이냐? \n>");
scanf_s("%s", messageBuffer, sizeof(messageBuffer));

for (i = 0; i < MAX_BUFFER; i++)
{
self_id[i] = messageBuffer[i];
}

bufferLen = strlen(messageBuffer);
send(listenSocket, messageBuffer, bufferLen, 0);
memset(&messageBuffer, 0, sizeof(messageBuffer));

recv(listenSocket, messageBuffer, MAX_BUFFER, 0);
count = atoi(messageBuffer);

for (i = 0; i < count; i++)
{
memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(listenSocket, messageBuffer, MAX_BUFFER, 0);
printf("현재 연결된 클라이언트 ID는 %s 이다.\n ", messageBuffer);
printf("%d 번째 받음\n", i);
}


while (1)
{
printf("수행할 사칙연산은 무엇이냐?(+,-,/,* 중 입력,나가기 q)\n ");
// 3-2. 연산자 보내기
memset(&messageBuffer, 0, sizeof(messageBuffer));
scanf_s("%s", messageBuffer, sizeof(messageBuffer));

if ((messageBuffer[0] == '+' || messageBuffer[0] == '-' || messageBuffer[0] == '/' || messageBuffer[0] == '*' || messageBuffer[0] == 'q') != 1) {

send(listenSocket, messageBuffer, MAX_BUFFER, 0); //첫번째 연산자입력
memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(listenSocket, messageBuffer, MAX_BUFFER, 0);
printf("%s. \n", messageBuffer);
continue;
}

if (messageBuffer[0] == 'q')
{
messageBuffer[1] = self_id[0];
send(listenSocket, messageBuffer, MAX_BUFFER, 0);
break;

}
else
{
send(listenSocket, messageBuffer, MAX_BUFFER, 0); //첫번째 연산자입력
memset(&messageBuffer, 0, sizeof(messageBuffer));

printf("첫번째수를 입력하라\n");
scanf_s("%s", messageBuffer, sizeof(messageBuffer));
send(listenSocket, messageBuffer, MAX_BUFFER, 0);// 두번째 숫자 1 입력
memset(&messageBuffer, 0, sizeof(messageBuffer));

printf("두번째수를 입력하라\n");
scanf_s("%s", messageBuffer, sizeof(messageBuffer));
send(listenSocket, messageBuffer, MAX_BUFFER, 0);// 세번째 숫자 2 입력

memset(&messageBuffer, 0, sizeof(messageBuffer));
recv(listenSocket, messageBuffer, MAX_BUFFER, 0);

printf("결과값은 %lf 이다.\n", atof(messageBuffer));

}

printf("나왔다!!");
}



// 4. 소켓종료

printf("서버와 연결이 끊겼습니다.\n");
closesocket(listenSocket);
WSACleanup();

getchar();
getchar();
return 0;
}

Guest의 이미지

Use code tag please.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.