안녕하세요. recv send 함수에 대한 질문드립니다.
글쓴이: K.I.D Neon (NK)... / 작성시간: 토, 2017/05/27 - 11:24오전
제가 pthread를 사용해서 간단한 채팅 프로그램 소스를 짰습니다.
그런데, 리눅스에서 send recv 함수를 사용해 쓰레드로 동기화 시켜 다음과 같이 구현했는데요.
Server Code
// Override int User::run() { char buf[User::MAXSTRLEN]; while(true) { try { recvMessage(buf); stringstream oss; oss << "(" << getIP() << ":" << getPort() << ") : " << buf; // 익셉션 메시지 로그,, sendMessageAll(oss.str().c_str()); // 모든 사용자에게 전달,, cout << "(" << getIP() << ":" << getPort() << ") : " << buf << endl; } catch(ChatException ex) { stringstream oss; oss << "(" << getIP() << ":" << getPort() << ") : " << "유저가 나갔습니다. "; sendMessageAll(oss.str().c_str()); printLeaveUser(*this); break; // 오류가 있으면, 서버가 종료. } } pthread_mutex_lock(&App::pMutex); int len = App::userList.size(); for(int i = 0; i < len; i++) { User *user = App::userList.at(i); // 사용자 목록에서 한 사용자를 가져옵니다,, if(user->getSocket() == this->getSocket()) { App::userList.erase(App::userList.begin() + i); // 사용자 리스트에서 끊어진 사용자 제거,, break; } } pthread_mutex_unlock(&App::pMutex); delete this; return 0; } void User::recvMessage(char *buf) { Message msg; int len = 0; memset(&msg, 0, sizeof(Message)); if(recv(this->recv_socket, (char*)&msg, sizeof(Message), 0) <= 0) { throw ChatException(SESSION_ERROR); } len = strnlen(msg.data, User::MAXSTRLEN); strncpy(buf, msg.data, strnlen(msg.data, User::MAXSTRLEN)); buf[len] = 0; } void User::sendMessageAll(const char *buf) { int len = App::userList.size(); for(int i = 0; i < len; i++) { User *user = App::userList.at(i); try { sendMessage(user->getSocket(), buf); } catch(ChatException ex) { throw ChatException(SEND_ERROR); } } } void User::sendMessage(int socket, const char *buf) { Message msg; memset(&msg, 0, sizeof(Message)); if(buf != nullptr) { int len = strnlen(buf, User::MAXSTRLEN); strncpy(msg.data, buf, len); msg.data[len] = 0; } pthread_mutex_lock(&App::pMutex); if(send(socket, (const char*)&msg, sizeof(Message), 0) <= 0) { pthread_mutex_unlock(&App::pMutex); throw ChatException(SESSION_ERROR); } pthread_mutex_unlock(&App::pMutex); }
Client Code
int ChatClient::run() { // 보내고 받는 스레드를 각각 만들어줌,, sendThread = new SendThread(this->client_socket); recvThread = new RecvThread(this->client_socket); connectServer(); // 서버 접속 시도... sendThread->start(); recvThread->start(); sendThread->join(); // sendThread가 종료될 때까지 계속 대기.. recvThread->join(); return sendThread->getExitCode(); // 혹여 서버가 죽을 경우, 반환할 값 (join 함수에서 받아야 함) } void sendRecvInterface::recvMessage(int socket, char *buf) { Message msg; int len = 0; memset(&msg, 0, sizeof(Message)); if(recv(socket, (char*)&msg, sizeof(Message), 0) <= 0) { throw ChatException(1100); } len = strnlen(msg.data, ChatClient::MAXSTRLEN); strncpy(buf, msg.data, len); buf[len] = 0; } void sendRecvInterface::sendMessage(int socket, const char* buf) { Message msg; memset(&msg, 0, sizeof(Message)); if(buf != nullptr) { int len = strnlen(buf, ChatClient::MAXSTRLEN); strncpy(msg.data, buf, len); msg.data[len] = 0; } pthread_mutex_lock(&App::pMutex); if(send(socket, (const char*)&msg, sizeof(Message), 0) <= 0) { pthread_mutex_unlock(&App::pMutex); throw ChatException(1100); } pthread_mutex_unlock(&App::pMutex); } void sendRecvInterface::gotoxy(int x, int y) { fprintf(stdout, "\033[%dd\033[%dG", y, x); } SendThread::SendThread(int cs) : client_socket(cs) {} int SendThread::run() { int result = -1; char buf[ChatClient::MAXSTRLEN]; while(true) { try { cin >> buf; cin.clear(); if(exitUser(buf)) { result = 0; throw ChatException(2100); } sendMessage(this->client_socket, buf); } catch(ChatException ex) { close(this->client_socket); break; } } return result; } bool SendThread::exitUser(const char *buf) { if(strcmp(buf, UserCommand::EXIT) == 0) { return true; } return false; } RecvThread::RecvThread(int cs) {} int RecvThread::run() { char buf[ChatClient::MAXSTRLEN]; while(true) { try { recvMessage(this->client_socket, buf); cout << buf << endl; } catch (ChatException ex) { close(this->client_socket); break; } } return 0; }
이렇게 구현을해서, 클라이언트에서 cin >> buf 쪽에서 입력을 기다리고, 메시지를 입력하면, 서버로 보내는 간단한 채팅 프로그램입니다. 그런데, 메시지를 입력하고, 엔터를 누르면 한 개의 메시지만 가는게 아니라 해당 메시지가 여러 번 송신이 되는데, 왜 그런걸까요? 고수님들의 도움을 부탁드립니다.
Forums:
댓글 달기