TCP 두 수 합 구하는 프로그램 작성
- 클라이언트에게 두 정수를 입력 받아서 서버가 데이터를 연산하여 보내준다
<TCPServerSum.cpp>
#include "Common.h"
#define SERVERPORT 9000
#define SIZE 512
int main() {
int retval;
// ===== 윈속 초기화 =====
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// ===== 소켓 생성 =====
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP 통신 소켓
if (listenSocket == INVALID_SOCKET) printf("Socket ERROR!!!\n");
// ===== bind() =====
struct sockaddr_in serveraddr; //IPv4 소켓 주소 구조체
memset(&serveraddr, 0, sizeof(serveraddr)); // 주소 초기화
serveraddr.sin_family = AF_INET; // IPv4
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADRR_ANY : 모든 IP에서 접속 가능!!
serveraddr.sin_port = htons(SERVERPORT); // h -> n Port Number 설정
retval = bind(listenSocket, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR) printf("BIND() ERROR!!\n");
// -- LISTEN() -- 대기 상태 변경, 클라이언트 갯수
retval = listen(listenSocket, SOMAXCONN);
if (retval == SOCKET_ERROR) printf("LISTEN() ERROR!!!\n");
printf("Server Listen...\n");
// 통신에 사용할 변수 선언
SOCKET clientSocket; // 클라이언트 소켓
struct sockaddr_in clientaddr; // 클라이언트 소켓 주소(원격 IP / 원격 PORT)
int addrlen; // 주소 길이
int num[2]; // 받은 데이터를 저장할 응용프로그램 버퍼
int result = 0; // 받은 데이터 결과
while (1) {
// ===== accept() =====
addrlen = sizeof(clientaddr);
clientSocket = accept(listenSocket, (struct sockaddr*)&clientaddr, &addrlen);
if (clientSocket == INVALID_SOCKET) {
printf("ACCEPT() ERROR!!\n");
break;
}
char addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientaddr.sin_addr, addr, sizeof(addr)); // inet_ntop : 네트워크 바이트 정렬
printf("TCP Connect : IP = %s, PORT = %d\n", addr, ntohs(clientaddr.sin_port));
// inet_ntop 네트워크 바이트 정렬(숫자) ->문자열로
// inet_btop(주소체계, IP주소, 저장공간, 크기)
while (1) {
// ===== recv() =====
retval = recv(clientSocket, (char*)num, sizeof(num), MSG_WAITALL); // recv(원격소켓, 버퍼, 버퍼크기, 0);
// 수신 버퍼에 있는 값을 읽어 와서 응용프로그램 버퍼에 복사
if (retval == SOCKET_ERROR) { // 오류가 있을 경우
printf("RECV() ERROR!!!\n");
break;
}
else if (retval == 0) break; // 정상 종료
printf("[TCP : %s : %d] %d %d\n", addr, ntohs(clientaddr.sin_port), num[0], num[1]);
// ===== send() =====
result = num[0] + num[1];
retval = send(clientSocket, (char*)&result, sizeof(result), 0);
if (retval == SOCKET_ERROR) {
printf("SEND() ERROR!!!\n");
break;
}
}
// 클라이언트 소켓 닫기
closesocket(clientSocket);
printf("Client 종료 IP = %s, Port Number = %d\n", addr, ntohs(clientaddr.sin_port));
}
// Listen Socket 닫기
closesocket(listenSocket);
// 윈속 종료
WSACleanup();
return 0;
}
- 서버는 클라이언트가 로 보내준 데이터를 recv()로 받아서 계산해서 send()로 전달해준다
<TCPClientSum.cpp>
#include "Common.h"
#define SERVERPORT 9000
#define BUFSIZE 512
char* SERVERIP = (char*)"127.0.0.1";
int main(int argc, char* argv[]) {
int retval;
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// 소켓 생성
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) printf("SOCKET ERORR!!!\n");
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr)); // 소켓 초기화
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, SERVERIP, &serveraddr.sin_addr);
serveraddr.sin_port = ntohs(SERVERPORT);
// ===== connect() =====
retval = connect(sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR) printf("CONNECT() ERORR!!!\n");
// 데이터 통신에 사용할 변수
int num[2];
int result = 0;
while (1) {
// 데이터 입력
printf("\n[보낼 두 정수 데이터] ");
scanf("%d %d", &num[0], &num[1]);
// ===== send() =====
retval = send(sock, (const char*)num, sizeof(num), 0);
if (retval == SOCKET_ERROR) {
printf("SEND() ERROR!!!\n");
break;
}
printf("[TCP Client] %dByte를 보냈습니다\n", retval);
// ===== recv() =====
retval = recv(sock, (char*)&result, sizeof(result), MSG_WAITALL);
if (retval == SOCKET_ERROR) {
printf("RECV() ERROR!!!\n");
break;
}
else if (retval == 0) break;
printf("[TCP Client] %dByte를 받았습니다\n", retval);
printf("[Result] %d\n", result);
}
closesocket(sock);
WSACleanup();
return 0;
}
- 클라이언트는 2개의 정수 데이터를 입력받고 send()로 보내서 결과를 recv()를 받는다
TCP 간단한 채팅(1:1 = 클라이언트 : 서버) 프로그램 작성
※단, 채팅 순서는 클라이언트, 서버 순서로 입력 한다!!
<TCPServerChat.cpp>
#include "Common.h"
#define SERVERPORT 9000 // 서버 포트
#define IDSIZE 16 // 서버의 채팅 ID 최대 길이 ( < > 기호 포함해서!!)
#define MSGSIZE 496 // 채팅 메시지 최대 길이
#define BUFSIZE (IDSIZE + MSGSIZE) // 버퍼의 전체 크기 = 채팅 ID 길이 + 메시지 길이
int main(int argc, char *argv[]) {
int retval;
if (argc != 2) {
fprintf(stderr, "Usage : %s <ChatID>\n", argv[0]);
exit(1);
}
// ===== (서버)채팅 아이디 길이 체크 =====
const char* chatid = argv[1];
if (strlen(chatid) > (IDSIZE - 2)) { // -2 : <> 기호 크기
fprintf(stderr, "<ChaID>의 최대 길이는 %d 입니다\n", (IDSIZE - 2));
exit(1);
}
// ===== 윈속 초기화 =====
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// ===== 소켓 생성 =====
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP 통신 소켓
if (listenSocket == INVALID_SOCKET) printf("Socket ERROR!!!\n");
// ===== bind() =====
struct sockaddr_in serveraddr; //IPv4 소켓 주소 구조체
memset(&serveraddr, 0, sizeof(serveraddr)); // 초기화
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADRR_ANY : 모든 IP에서 접속 가능!!
serveraddr.sin_port = htons(SERVERPORT);
retval = bind(listenSocket, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR) printf("BIND() ERROR!!\n");
// ===== listen() =====
retval = listen(listenSocket, SOMAXCONN);
if (retval == SOCKET_ERROR) printf("LISTEN() ERROR!!!\n");
//printf("Server Listen...");
// 통신에 사용할 변수 선언
SOCKET clientSocket; // 클라이언트 소켓
struct sockaddr_in clientaddr; // 클라이언트 소켓 주소(원격 IP / 원격 PORT)
int addrlen; // 주소 길이
int len;
char msg[MSGSIZE + 1]; // 입력 메시지 저장
char buf[BUFSIZE + 1]; // 받은 메세지를 저장할 응용프로그램 버퍼
while (1) {
// ===== accept() =====
addrlen = sizeof(clientaddr);
clientSocket = accept(listenSocket, (struct sockaddr*)&clientaddr, &addrlen);
if (clientSocket == INVALID_SOCKET) {
printf("ACCEPT() ERROR!!\n");
break;
}
// 접속한 클라이언트의 IP, Port 출력
char addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientaddr.sin_addr, addr, sizeof(addr)); // inet_ntop : 네트워크 바이트 정렬
printf("TCP Connect : IP = %s, PORT = %d\n", addr, ntohs(clientaddr.sin_port));
// ===== 클라이언트와 통신 =====
while (1) {
// ===== recv =====
// === 고정길이 데이터 받기 ===
retval = recv(clientSocket, (char*)&len, sizeof(int), MSG_WAITALL);
if (retval == SOCKET_ERROR) { // 오류가 있을 경우
printf("FIXED_LENGHT_DATA RECV() ERROR!!!\n");
break;
}
else if (retval == 0) break; // 정상 종료
// === 가변 길이 메시지 받기 ===
retval = recv(clientSocket, buf, len, MSG_WAITALL);
if (retval == SOCKET_ERROR) {
printf("VARIABLE_LENGTH_DATA RECV() ERROR!!!\n");
break;
}
else if (retval == 0) break;
// 받은 메시지 출력
buf[retval] = '\0';
printf("%s", buf);
// 메시지 입력
printf("<%s>", chatid);
if (fgets(msg, MSGSIZE + 1, stdin) == NULL) {
break;
}
// '\n' 문자 제거
len = (int)strlen(msg);
if (msg[len - 1] == '\n') msg[len - 1] = '\0';
if (strlen(msg) == 0) break;
// 메시지 준비하기;
sprintf(buf, "<%s> %s\n", chatid, msg);
len = (int)strlen(buf);
// ===== send() =====
// ===== 고정 크기 데이터 보내기(메시지 길이) =====
retval = send(clientSocket, (char *)&len, sizeof(int), 0);
if (retval == SOCKET_ERROR) {
printf("FIX_DATA_SEND_ERROR!!!\n");
break;
}
// ===== 가변 크기 메시지 보내기 (메시지) =====
retval = send(clientSocket, buf, len, 0);
if (retval == SOCKET_ERROR) {
printf("VAR_MSG_SEND_ERROR!!!\n");
break;
}
}
// 클라이언트 소켓 닫기
closesocket(clientSocket);
printf("Client 종료 IP = %s, Port Number = %d\n", addr, ntohs(clientaddr.sin_port));
}
// Listen Socket 닫기
closesocket(listenSocket);
// 윈속 종료
WSACleanup();
return 0;
}
- 고정 길이 데이터에 가변 길이 데이터의 길이를 입력 받아 가변길이 데이터를 처리한다
- 서버의 아이디는 "프로젝트 속성 -> 구성 속성 -> 디버깅 -> 명령인수"에 입력 한다
<TCPClientChat.cpp>
#include "Common.h"
#define SERVERPORT 9000 // 통신할 서버 포트
#define IDSIZE 16 // (클라이언트) 채팅 ID 최대 길이 (<> 기호 포함!!)
#define MSGSIZE 240 // 채팅 메시지 최대 길이
#define BUFSIZE (IDSIZE + MSGSIZE) // 버퍼 전체 크기 = 채팅 ID 길이 + 채팅 메시지 길이
char* SERVERIP = (char*)"127.0.0.1";
int main(int argc, char *argv[]) {
int retval;
if (argc != 3) {
fprintf(stderr, "Usage : %s <IP> <ChaID>\n", argv[0]);
exit(1);
}
// 명령행 인수가 있으면 IP주소로 사용하기!
if (argc > 1) SERVERIP = argv[1];
// 명령행 인수로 전달된 ID를 저장, 길이 점검
const char* chatid = argv[2];
if (strlen(chatid) > (IDSIZE - 2)) {
fprintf(stderr, "<ChatID>의 최대 길이는 %d 입니다", (IDSIZE-2));
exit(1);
}
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// 소켓 생성
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) printf("SOCKET ERORR!!!\n");
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr)); // 소켓 초기화
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, SERVERIP, &serveraddr.sin_addr);
serveraddr.sin_port = htons(SERVERPORT);
// ===== connect() =====
retval = connect(sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR) printf("CONNECT() ERORR!!!\n");
// 데이터 통신에 사용할 변수
char msg[MSGSIZE + 1]; // 입력 메시지 저장
char buf[BUFSIZE + 1]; // 받은 메시지를 저장할 응용프로그램 버퍼
int len; // 입력한 문자 길이 정리
// 서버와 데이터 통신
while(1){
// 메시지 입력
printf("<%s> ", chatid);
if (fgets(msg, MSGSIZE + 1, stdin) == NULL) break;
// '\n' 문자 제거
len = (int)strlen(msg);
if (msg[len - 1] == '\n') msg[len - 1] = '\0';
if (strlen(msg) == 0) break;
// 메시지 준비!
sprintf(buf, "<%s> %s\n", chatid, msg);
len = (int)strlen(buf);
// ===== send() =====
// 고정 길이 데이터 보내기
retval = send(sock, (char*)&len, sizeof(int), 0);
if (retval == SOCKET_ERROR) {
printf("FIXED_LENGHT_MSG SEND() ERROR!!!\n");
break;
}
// 가변길이 메시지 보내기
retval = send(sock, buf, len, 0);
if (retval == SOCKET_ERROR) {
printf("VARIABLE_LENGTH_MSG SEND() ERROR!!!\n");
break;
}
// ===== recv() =====
// 고정 길이 데이터 받기
retval = recv(sock, (char*)&len, sizeof(int), MSG_WAITALL);
if (retval == SOCKET_ERROR) {
printf("FIXED_LENGHT_MSG RECV() ERROR!!!\n");
break;
} else if (retval == 0){
break;
}
// 가변 길이 메시지 받기
retval = recv(sock, buf, len, MSG_WAITALL);
if (retval == SOCKET_ERROR) {
printf("VARIABLE_LENGTH_MSG RECV() ERROR!!!\n");
break;
} else if (retval == 0) {
break;
}
// 받은 메시지 출력!
buf[retval] = '\0';
printf("%s", buf);
}
// 소켓 닫기
closesocket(sock);
// 윈속 종료
WSACleanup();
return 0;
}
- 고정 길이 데이터에 가변 길이 데이터의 길이를 입력 받아 가변길이 데이터를 처리한다
- 클라이언트의 아이디와 서버 IP주소는 "프로젝트 속성 -> 구성 속성 -> 디버깅 -> 명령인수"에 입력 한다
'개인 공부 > 네트워크' 카테고리의 다른 글
네트워크P-009 (스레드 생성 & 종료) (0) | 2023.04.20 |
---|---|
네트워크P-008(스레드 & [이전 실습] 파일 전송) (1) | 2023.04.16 |
네트워크P-007 (데이터 전송 실습) (1) | 2023.04.15 |
네트워크P-006 (데이터 전송 방식) (1) | 2023.04.13 |
네트워크P-005(TCP Server, TCP Client ) (2) | 2023.04.12 |