// Server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
void ErrorHandling(char* message);
int main(int argc, char* argv[]) {
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;
int szClntAddr;
char message[] = "Hello World!";
// argc가 2가 아니라면 즉, 포트번호가 설정이 안되었다면 종료
if (argc != 2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
// Winsock 라이브러리의 초기화를 수행
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
ErrorHandling("WSAStartup() error!");
}
// 소켓을 생성하며, 이 소켓은 서버와 클라이언트 간의 연결에 사용
hServSock = socket(PF_INET, SOCK_STREAM, 0);
if (hServSock == INVALID_SOCKET) {
ErrorHandling("socket() error!");
}
// servAddr 구조체를 0으로 초기화
// INADDR_ANY를 사용하여 소켓이 동작하는 컴퓨터의 IP주소를 자동으로 할당
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(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
ErrorHandling("bind() error!");
}
// 클라이언의 연결 요청을 기다리기 시작
// 연결 요청 대기 큐의 크기를 5로 설정하여 클라이언트의 연결 요청을 5개까지 대기 가능
if (listen(hServSock, 5) == SOCKET_ERROR) {
ErrorHandling("listen() error!");
}
// 클라이언트의 연결 요청을 수락하고, 연결된 클라이언트와의 통신을 위한 새로운 소켓을 반환
szClntAddr = sizeof(clntAddr);
hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);
if (hClntSock == INVALID_SOCKET) {
ErrorHandling("accept() error!");
}
// 연결된 클라이언트에게 "Hello World!" 메시지를 전송
send(hClntSock, message, sizeof(message), 0);
// 더 이상 필요하지 않은 소켓을 닫기
closesocket(hClntSock);
closesocket(hServSock);
// Winsock 라이브러리의 사용을 종료하고, 할당된 리소스를 해제
WSACleanup();
return 0;
}
void ErrorHandling(char* message) {
fputs(message, stderr);
fputs("\n", stderr);
exit(1);
}
// Client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
void ErrorHandling(char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
char message[30];
int strLen = 0;
int idx = 0, readLen = 0;
// argc가 3이 아니라면 즉, IP와 포트번호가 설정이 안되었다면 종료
if (argc != 3) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
ErrorHandling("WSAStartup() error!");
}
hSocket = socket(PF_INET, SOCK_STREAM, 0);
if (hSocket == INVALID_SOCKET) {
ErrorHandling("socket() error!");
}
// 사용자가 제공한 IP주소, 포트번호를 알맞는 형식으로 변환
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]));
// 위에서 설정한 서버의 주소와 포트번호에 연결 시도
if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
ErrorHandling("connect() error!");
}
// 서버로부터 데이터를 1바이트씩 수신
while (readLen = recv(hSocket, &message[idx++], 1, 0)) {
if (readLen == -1) {
ErrorHandling("read() error!");
}
strLen += readLen;
}
// 서버로부터 받은 메세지와 길이를 출력
printf("Message from server: %s \n", message);
printf("Function read call count: %d", strLen);
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char* message) {
fputs(message, stderr);
fputs("\n", stderr);
exit(1);
}
포트번호를 9190을 설정한 후 실행 결과
서버에서 설정한 Hello World! 메세지를 클라이언트에서 수신했다.
'네트워크' 카테고리의 다른 글
소켓 프로그래밍 - Iterative 에코 서버 (0) | 2023.09.10 |
---|---|
ReaderWriterLock 구현 (0) | 2023.08.05 |
ReaderWriterLock (0) | 2023.08.04 |
AutoResetEvent (0) | 2023.08.03 |
SpinLock (0) | 2023.08.02 |