250930

lililllilillll·2025년 9월 30일

개발 일지

목록 보기
310/350

✅ 한 것들


  • 윤성우의 열혈 TCP/IP 소켓 프로그래밍


📖 윤성우의 열혈 TCP/IP 소켓 프로그래밍


04-4 윈도우 기반 구현

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 1024
void ErrorHandling(char *message);

int main(int argc, char *argv[])
{
	WSADATA wsaData;
	SOCKET hServSock, hClntSock;
	char message[BUF_SIZE];
	int strLen, i;

	SOCKADDR_IN servAdr, clntAdr;
	int clntAdrSize;

	if(argc!=2) {
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}

	if(WSAStartup(MAKEWORD(2,2), &wsaData)!=0)
		ErrorHandling("WSAStartup() error!");

	hServSock=socket(PF_INET, SOCK_STREAM, 0);
	if(hServSock==INVALID_SOCKET)
		ErrorHandling("socket() error");

	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family=AF_INET;
	servAdr.sin_addr.s_addr=htonl(INADDR_ANY);
	servAdr.sin_port=htons(atoi(argv[1]));

	if(bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr))==SOCKET_ERROR)
		ErrorHandling("bind() error");

	if(listen(hServSock, 5)==SOCKET_ERROR)
		ErrorHandling("listen() error");

	clntAdrSize=sizeof(clntAdr);

	for(i=0; i<5; i++)
	{
		hClntSock=accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);
		if(hClntSock==-1)
			ErrorHandling("accept() error");
		else
			printf("Connected client %d \n", i+1);

		while((strLen=recv(hClntSock, message, BUF_SIZE, 0))!=0)
			send(hClntSock, message, strLen, 0);

		closesocket(hClntSock);
	}
	closesocket(hServSock);
	WSACleanup();
	return 0;
}

void ErrorHandling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

echo_server_win.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 1024
void ErrorHandling(char *message);

int main(int argc, char *argv[])
{
	WSADATA wsaData;
	SOCKET hSocket;
	char message[BUF_SIZE];
	int strLen;
	SOCKADDR_IN servAdr;

	if(argc!=3) {
		printf("Usage : %s <IP> <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");

	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = inet_addr(argv[1]);
	servAdr.sin_port = htons(atoi(argv[2]));

	if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr))==SOCKET_ERROR)
		ErrorHandling("Connect() error!");
	else
		puts("Connected........");

	while(1)
	{
		fputs("Input message(Q to quit): ", stdout);
		fgets(message, BUF_SIZE, stdin);

		if(!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
			break;

		send(hSocket, message, strlen(message), 0);
		strLen = recv(hSocket, message, BUF_SIZE-1, 0);
		message[strLen] = 0;
		printf("Message from server: %s", message);
	}
	closesocket(hSocket);
	WSACleanup();
	return 0;
}

void ErrorHandling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

echo_client_win.c

Chapter 5 TCP 기반 서버/클라 2

05-1 에코 클라이언트 완벽 구현

문제가 되는 건 에코 클라

  • 데이터를 한 방에 전송해버린다
  • 받는 것도 한 방에 받기를 원한다
  • 에코 클라 한정으로, 받을 데이터 크기 알고 있으니 해결은 쉽다
str_len = write(sock, message, strlen(message))l

recv_len = 0;
while(recv_len < str_len)
{
	recv_cnt = read(sock, &message[recv_len], BUF_SIZE-1};
	if(recv_cnt==-1)
		error_handling("read() error!");
	recv_len += recv_cnt;
}

기존 클라에 위 코드를 추가하면 해결된다

에코 클라가 아니라면,
데이터의 끝을 파악할 수 있는 약속을 별도로 정의하거나
송수신될 데이터의 크기를 미리 알려주는 등
'어플리케이션 프로토콜'을 정의하여 해결한다



profile
너 정말 **핵심**을 찔렀어

0개의 댓글