수다닷컴

  • 해외여행
    • 괌
    • 태국
    • 유럽
    • 일본
    • 필리핀
    • 미국
    • 중국
    • 기타여행
    • 싱가폴
  • 건강
    • 다이어트
    • 당뇨
    • 헬스
    • 건강음식
    • 건강기타
  • 컴퓨터
    • 프로그램 개발일반
    • C언어
    • 비주얼베이직
  • 결혼생활
    • 출산/육아
    • 결혼준비
    • 엄마이야기방
  • 일상생활
    • 면접
    • 취업
    • 진로선택
  • 교육
    • 교육일반
    • 아이교육
    • 토익
    • 해외연수
    • 영어
  • 취미생활
    • 음악
    • 자전거
    • 수영
    • 바이크
    • 축구
  • 기타
    • 강아지
    • 제주도여행
    • 국내여행
    • 기타일상
    • 애플
    • 휴대폰관련
  • 프로그램 개발일반
  • C언어
  • 비주얼베이직

채팅프로그래밍을 서버와 클라이언트 창을 하나로할려면 어떻게해야하죠 ??

사이

2023.04.01

서버와 클라이언트 따로 실행시켜서 다른컴퓨터와 1:1채팅을 하였습니다. 이것을 하나의 프로젝트로 콘솔창 하나로 서버와 클라이언트에서 데이터를 주고받을순 없나요?
#include winsock2.h
#include stdio.h
#include stdlib.h
void ErrorDisplay(char *szError);
void ErrorPrint(char *szError);
void main()
{
int ret;
WSADATA wsa;
SOCKET s;
SOCKADDR_IN saddr;
SOCKADDR_IN caddr;
int caddrlen;
SOCKET cs;
int nSend;
/*
함수 : int WSAStartup(WORD wVersionRezuested, LPWSADATA lpWSAData);
기능 : WS2_32.DLL의 사용을 초기화 한다.
인수 : 버전, WSADATA 구조체 번지.
셜명 : 보통 winsock 2.2를 사용, 설정을 위하여 MAKEWORD(2,2)를 사용
반환 : 성공 시 0, 실패 시 에러 코드
주의 : 이 함수는 특별한 경우가 아니면, 한 프로그램에 한 번만 호출 된다.
*/
ret = WSAStartup(MAKEWORD(2,2),&wsa);
if(ret != 0){
ErrorDisplay(WSAStartup);
}
/*
함수 : SOCKET socket(lnt af,int type,int protocol);
기능 : 소켓을 생성
인수 : 1. AF_INET == TCP/IP,UDP일 경우 사용,
2. SOCK_STREAM(TCP/IP) 또는 SOCK_DGRAM(UDP)
3. IPPROTO_TCP(TCP/IP) 또는 IPPROTO_UDP(UDP),일반적으로 0사용
설명 :소켓 디스크립터를 생성하고 , 필요 자원을 할당한다.
반환 : 성공 시 소켓 디스크립터, 실패시 INVALID_SOCKET
*/
s = socket(AF_INET,SOCK_STREAM,0);
if(s==INVALID_SOCKET){
ErrorDisplay(socket());
}
/*
함수 : int bind(SOCKET s, const struct sockaddr FAR* name,int namelen);
기능 : 생성된 소켓 s에 네트워크 주소와 포트 번호를 연결한다.
인수 : 1. socket 함수에 의해 생성된 소켓 디스크립터(s)
2. SOCKADDR_IN 구조체.(SOCKADDR* 또는 struct sockaddr FAR*)
구조체는 주소체계(AF_INET),port,네트워크 주소로 채워져야 함.
3. SOCKADDR_IN 구조체의 크기
설명 : 생성된 소켓 s 디스크립터에 포트번호와 네트워크 주소를 설정.
반환 : 성공 시 0, 실패시 SOCKET_ERROR
보충 : htons, htonl은 호스트의 바이트 순서를 네트워크 바이트 순서로 바꿔주는
함수. inet_addr()함수는 네트워크 주소를 4바이트의 IN_ADDR구조로 바꿔준다.
*/
ZeroMemory(&saddr,sizeof(saddr));
saddr.sin_family = AF_INET; // 주소체계
saddr.sin_port = htons(5000); // 포트 번호
saddr.sin_addr.s_addr = htonl(INADDR_ANY); // 네트워크 카드 설정
//saddr.sin_addr.s_addr = inet_addr(127.0.0.1);
ret = bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
if(ret == SOCKET_ERROR){
ErrorDisplay(bind());
}
/*
함수 : int listen(SOCKET s,int backing);
기능 : 클라이언트 접속을 받을 수 있는 대기 상태로 진입한다.
인수 : 1. socket 함수에 의해 생성된 소켓 디스크립터
2. 동시에 접근 가능한 최대 클라이언트수.
설명 : 이 함수를 호출 하면 클라이언트가 접속 할 수 있다.
반환 : 성공 시 0, 실패시 SOCKET_ERROR
주의 :backog 값이 5이면 , 동시 접속자 수는 5이기 때문에 경우에 따라
사용자가 많은 서버 에서는 접속 실패가 빈번하게 일어남.
윈도우 환경에서 이값은 SOMAXCONN이 권장,
UNIX나 Linux에서는 해당 시스템에 맞게 값을 적절히 조정해야함.
*/
ret = listen(s,SOMAXCONN);
if(ret == SOCKET_ERROR){
ErrorDisplay(listen());
}
while(TRUE){

/*
함수 : SOCKET accept(SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen);
기능 : 접속된 클라이언트를 받아 들인다.
인수 : 1. socket 함수에 의해 생성된 소켓 디스크립터
2. SOCKADDR_IN 구조체.구조체는 주소체계(AF_INET),port,네트워크 주소로 채워진다.
3.SOCKADDR_IN 구조체의 크기
설명 : listen 함수에 의해 클라이언트의 접속이 허용되면, 클라이언트가 접속해온다.
accept 삼수는 클라이언트가 접속할 경우 ,그와 연관된 소켓을 생성하여 반환한다.
반환 : 성공 시 새로 생성된 SOCKET 디스크립터, 실패 시 INVAID_SOCKET
주의 : accept 함수는 블로킹 함수이다. 블로킹이란 함수 호출 시 더 이상 진행하지 않고
함수 내에서 멈춰져 있다는 것.
*/

caddrlen =sizeof(caddr);
cs = accept(s,(SOCKADDR*)&caddr,&caddrlen);
if(cs == INVALID_SOCKET){
ErrorPrint(accept());
continue;
}
/************************************************************************/
/* 클라이언트 정보 표시
inet_ntoa() 함수는 IN_ADDR 구조체의 값을 문자열로 변환 해준다.
ntohs() 함수는 네트워크 바이트 오더의 포터 번호를 호스트에
맞게 변환 해준다. */
/************************************************************************/
printf(클라이언트 IP : %s\n,inet_ntoa(caddr.sin_addr));
printf(클라tf(클라이언트 port: %d\n,ntohs(caddr.sin_port));
//클라이언트의 데이터 수신 및 재송신(Echo Server)
while(TRUE){
char buf[1024];
int nRecv;
memset(buf,0,sizeof(buf));
/************************************************************************/
/* 함수 :int recv(SOCKET s, char FAR* buf,int len,int flags);
기능 : TCP/IP를 통해 데이터를 수신한다.
인수 : 1.accept 함수에 의해 생성된 소켓 디스크립터
2.데이터를 수신할 버퍼
3.수신할 바이트의 최대값
4.일반적으로는 0,MSG_REEK또는 MSG_OOB사용 가능.
MSG_PEEK는 데이터를 읽어오고 수신 버퍼를 비우지 않는다.
일반적으로는 수신 버퍼는 데이터를 읽어온 후 비어진다.
설명 : 데이터를 수신한다.
반환 : 성공 시 수신된 바이트 수(항상 0보다 크다),실패 시 SOCKET_ERROR.
클라이언트와 접속이 단절 시 0.
주의 : recv 함수는 블로킹 함수 */
/************************************************************************/
nRecv = recv(cs,buf,sizeof(buf),0);
if(nRecv == SOCKET_ERROR){
ErrorPrint(recv());
break;
}
else if(nRecv == 0){
printf(클라이언트와의 접속이 끊어졌습니다.\n);
}
else{
//받은 데이터 출력
printf(%d 바이트 수신 :%s\n,nRecv,buf);
/************************************************************************/
/* 함수 : int send(SOCKET s,const char FAR *buf,int len,int flags);
기능 : TCP/IP를 통해 데이터를 전송한다.
인수 : 1. accept 함수에 의해 생성된 소켓 디스크립터
2. 데이터를 전송할 버퍼.
3. 전송할 바이트 수
4. 일반적으로는 0,MSG_DONTROUTE 또는 MSG_OOB 사용가능
MSG_DONTROUTE는 로클 라우팅 테이블을 참조 하지 않도록 설정.
MSG_OOB는 긴급 데이터를 보낼 때 사용, 잘사용하지 않는다.
설명 : 데이터를 전송한다.
반환 : 성공 시 전송된 바이트 수, 실패 시 SOCKET_ERROR.
주의 : send 함수는 블로킹 함수 이다. */
/************************************************************************/
nSend = send(cs,buf,nRecv,0);
if(nSend == SOCKET_ERROR){
ErrorPrint(send());
break;
}
}
}
/************************************************************************/
/* 함수 : int closesocket( SOCKET s );
기능 : 소켓을 닫고, 자원을 해제한다.
인수 : 1. 닫을 소켓 디스크립터(s 또는 cs)
설명 : 소켓을 닫는다.
반환 : 성공 시 0, 실패 시 SOCKET_ERROR.
주의 : closesocket 함수 사용 시 SO_LINGER 옵션과
SO_DONTLINGER 옵션의 영향을 받기 때문에 주의하자.
아래의 표에 보면,
SO_LINGER의 설정 값이 l_onoff는 0이고, l_linger도 0일 때에는
즉시 닫힘(hard close)이 발생하여 소켓은 즉시 제거되고,
대기 중인 송수신 데이터는 모두 잃게 된다.
안전한 데이터 송수신의 종료를 위해서는 shutdown 함수를 사용하는 것이 좋다.
----------------------------------------------------------------------------------
옵션 | 타임아웃간격 | 닫힘유형 | 닫힘대기여부 | 비 고
----------------------------------------------------------------------------------
SO_DONTLINGER | 상관 없음 | 정상 | 블록 안됨 | 데이터 안전 전송
SO_LINGER | 0 | hard | 블록 안됨 | 데이터 손실 가능
SO_LINGER | 0 | 정상 | 블록 됨 | 일정시간 데이터 전송
----------------------------------------------------------------------------------
SO_LINGER 옵션은 다음과 같이 설정할 수 있다. 이렇게 설정하면 closesocket 함수
사용 시 60초간 대기하면서 큐에 있는 데이터를 전송한다. 만약 전송이 완료되면,
60초가 되기 전에 블록이 해제된다. 중요한 데이터를 송신 중일 때는 이 방법을
사용하는 것이 좋다. 물론 closesocket 함수는 기본적으로 SO_DONTLINGER 옵션이
있기 때문에 이 방법을 사용하지 않아도 된다.
LINGER linger = { 1, 60 }; // 1(기능 사용), 종료 시 60 초간 대기 설정
if( setsockopt( s, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger) ) != 0 )
{
printf( 종료 설정 실패, 에러코드 = %d \n, WSAGetLastError() );
closesocket( s ); // 소켓 제거
WSACleanup(); // WS2_32.DLL 사용 종료
return;
} */
/************************************************************************/
closesocket( cs );
}

// 서버 접속용 소켓을 해제한다.
closesocket( s );
/************************************************************************/
/* 함수 : int&nbs int WSACleanup( void );
기능 : WS2_32.DLL의 사용을 종료한다.
인수 : 1. 닫을 소켓 디스크립터(s 또는 cs)
설명 : WS2_32.DLL의 사용을 종료한다.
반환 : 성공 시 0, 실패 시 SOCKET_ERROR.
주의 : 프로그램이 닫혀지기 전에 한 번만 호출하면 된다.
만약 프로그램이 실행 중에 이 함수를 호출한다면 모든 소켓은 종료된다. */
/************************************************************************/
WSACleanup();
}
/************************************************************************/
/*
함수 : void ErrorDisplay( char *szError )
기능 : 메시지 박스에 에러를 표시하고, 프로그램을 종료(exit)한다.
인수 : WSAGetLastError()-가장 최근에 발생한 소켓 에러의 번호를 리턴함
설명 : FormatMessage 함수는 내부적으로 버퍼를 할당하고, 가장 최근에 발생한
에러에 대한 메시지를 생성한다. 생성된 메시지의 버퍼는 포인터 변수인
lpBuff가 받아 온다.
주의 : FormatMessage 함수는 내부적으로 메모리를 할당하기 때문에 LocalFree
함수를 호출하여 메모리를 해제하여야 한다. */
/************************************************************************/
void ErrorDisplay(char *szError)
{
LPVOID lpBuff;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
WSAGetLastError(), // 에러 코드를 읽어 옴
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpBuff,
0,
NULL );
MessageBox( NULL, (LPCTSTR)lpBuff, szError, MB_ICONSTOP );
LocalFree( lpBuff );
exit( 0 ); // 프로그램을 종료
}
/************************************************************************/
/*
함수 : void ErrorPrint( char *szError )
기능 : 메시지 박스에 에러를 표시하고, 프로그램을 종료(exit)한다.
인수 : WSAGetLastError()-가장 최근에 발생한 소켓 에러의 번호를 리턴함
설명 : FormatMessage 함수는 내부적으로 버퍼를 할당하고, 가장 최근에 발생한
에러에 대한 메시지를 생성한다. 생성된 메시지의 버퍼는 포인터 변수인
lpBuff가 받아 온다.
주의 : FormatMessage 함수는 내부적으로 메모리를 할당하기 때문에 LocalFree
함수를 호출하여 메모리를 해제하여야 한다. */
/************************************************************************/
void ErrorPrint(char *szError)
{
LPVOID lpBuff;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&lpBuff,
0,
NULL);
printf(%s : %s\n,szError,lpBuff);
LocalFree(lpBuff);
}
------------------------------클라이언트 ------------------------------------
#include winsock2.h
#include stdio.h
#include stdio.h
void ErrorDisplay(char *szError);
void ErrorPrint(char *szError);
void main()
{
int ret;
WSADATA wsa;
SOCKET s;
SOCKADDR_IN saddr;
ret=WSAStartup(MAKEWORD(2,2),&wsa);
if(ret != 0){
ErrorDisplay(WSAStartup);
}
s = socket(AF_INET,SOCK_STREAM,0);
if(s == INVALID_SOCKET){
ErrorDisplay(socket());
}
/************************************************************************/
/* 함수 : int connect( SOCKET s, const struct sockaddr FAR* name, int namelen );
기능 : 서버에 접속한다.
인수 : 1. socket 함수에 의해 생성된 소켓 디스크립터(s)
2. SOCKADDR_IN 구조체. (SOCKADDR*는 struct sockaddr FAR*)
구조체는 주소체계(AF_INET), Port, 네트워크 주소로 채워진다.
3. SOCKADDR_IN 구조체의 크기
설명 : 대기 중인 서버에 접속한다. 접속 IP는 127.0.0.1로 한다.
반환 : 성공 시 0, 실패 시 SOCKET_ERROR
주의 : connect 함수는 블로킹 함수이다. 접속이 완료되었을 때 또는 실패 되었을 때만
함수는 리턴한다. */
/************************************************************************/
saddr.sin_family = AF_INET;
saddr.sin_port = htons(5000);
saddr.sin_addr.s_addr = inet_addr(127.0.0.1);
ret = connect(s,(SOCKADDR*)&saddr,sizeof(saddr));
if(ret != 0){
ErrorDisplay(connect());
}
while(TRUE){
char buf[1024];
int nSend;
int nRecv;
memset( buf, 0, sizeof buf );
gets( buf );
// scanf(%s,buf); //공백 포함을 안함..!!
nSend = send(s,buf,strlen(buf),0);
if(nSend == SOCKET_ERROR){
ErrorPrint(send());
break;
}
nRecv = recv(s,buf,sizeof(buf),0);
if(nRecv == SOCKET_ERROR){
ErrorPrint(recv());
break;
}
else if(nRecv == 0){
printf(클라이언트와 접속이 끊어졌습니다.\n);
break;
}
else{
printf( %d 바이트 수신 : %s \n, nRecv, buf );
}
}
closesocket( s );
WSACleanup();
}
void ErrorPrint(char *szError)
{
LPVOID lpBuff;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&lpBuff,
0,
NULL);
printf(%s : %s\n,szError,lpBuff);
LocalFree(lpBuff);
}
void ErrorDisplay(char *szError)
{
LPVOID lpBuff;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
WSAGetLastError(), // 에러 코드를 읽어 옴
MAKELAN MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpBuff,
0,
NULL );
MessageBox( NULL, (LPCTSTR)lpBuff, szError, MB_ICONSTOP );
LocalFree( lpBuff );
exit( 0 ); // 프로그램을 종료
}

신청하기





COMMENT

댓글을 입력해주세요. 비속어와 욕설은 삼가해주세요.

번호 제 목 글쓴이 날짜
2694827 이제 어떻게 공부해야할지 모르겠네요 새얀 2025-05-14
2694778 순열 계산요. 맛조이 2025-05-14
2694754 ShowWindow 함수를 이용하려 하는데 질문있습니다. (2) 파도 2025-05-14
2694731 리눅스 커널의 시작점 질문 미르 2025-05-13
2694702 이거 뭐가문제인가요 코드수정좀 (3) 맑은 2025-05-13
2694675 C언어 후위표기를 중위표기로 앨런 2025-05-13
2694646 안녕하세요 파일 합치기 함수! (1) 연블루 2025-05-13
2694618 잘몰라서 설명부탁드립니다. scanf 관련 (3) 파라 2025-05-12
2694590 이 코드가 뭐하는 코드일까요? #2 빵순 2025-05-12
2694559 동적할당으로 배열(2차원열)을 만드는데 있어 그걸 함수화시키는데... (1) 늘솔길 2025-05-12
2694532 네트워크에 관하여... (4) 황소자리 2025-05-12
2694503 프로그램 연산 후 바로 종료되는 현상 (6) Judicious 2025-05-11
2694450 while문질문입니다. (1) 허리품 2025-05-11
2694420 C언어 질문할게요(유니코드,자료형,버퍼,캐스트연산자) 은새 2025-05-11
2694370 내일까진데 함수호출 제발 도와주세요!!!!!!!!!11 들찬 2025-05-10
2694339 putchar()의 괄호 안에 int c=10;로 전에 선언된 c를 넣으면 안되는 이유에서 제가 생각한 것이 그 이유가 되는지 확인하고 싶습니다. (3) 미르 2025-05-10
2694316 이 코드 어디가 잘못되었는지 고수분들 ㅠㅠ (2) 나빛 2025-05-10
2694285 언어 공부하는 과정 좀 추천해주세요! (1) 아빠몬 2025-05-09
2694258 카운터.. 질문입니다. (4) 하늘빛눈망울 2025-05-09
2694229 단순한 질문이요 (8) 여름 2025-05-09
<<  이전  1 2 3 4 5 6 7 8 9 10  다음  >>

수다닷컴 | 여러분과 함께하는 수다토크 커뮤니티 수다닷컴에 오신것을 환영합니다.
사업자등록번호 : 117-07-92748 상호 : 진달래여행사 대표자 : 명현재 서울시 강서구 방화동 890번지 푸르지오 107동 306호
copyright 2011 게시글 삭제 및 기타 문의 : clairacademy@naver.com