#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#define BUF_SIZE 1024
void ErrorHandling(char *message);
int SumAll(int *msgBuf, int recvCount)
{
int result = 0;
for(int i=0; i<recvCount; i++) result += msgBuf[i];
return result;
}
int SubtractAll(int *msgBuf, int recvCount)
{
if(recvCount == 0) return 0;
int result = msgBuf[0];
for(int i=1; i<recvCount; i++) result -= msgBuf[i];
return result;
}
int MultiplyAll(int *msgBuf, int recvCount)
{
if(recvCount == 0) return 0;
int result = 1;
for(int i=0; i<recvCount; i++) result *= msgBuf[i];
return result;
}
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
char message[BUF_SIZE];
int msgBuf[BUF_SIZE];
int strLen, i, j, recvCount;
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);
recvCount = 0;
while(1)
{
int msgLen = recv(hClntSock, message, BUF_SIZE, 0);
printf("msgLen : %d\n", msgLen);
char *s = message;
while(*s==' '||*s=='\t'||*s=='\r'||*s=='\n') s++;
char *e = s + strlen(s);
while(e>s && (e[-1]==' '||e[-1]=='\t'||e[-1]=='\r'||e[-1]=='\n')) e--;
*e = '\0';
if(strcmp(message,"+") == 0 ||strcmp(message,"-") == 0 || strcmp(message,"*") == 0) { break; }
else
{
msgBuf[recvCount] = atoi(message);
recvCount++;
send(hClntSock,message,strlen(message),0);
}
}
int result = 0;
if(strcmp(message,"+") == 0) result = SumAll(msgBuf, recvCount);
else if (strcmp(message,"-") == 0) result = SubtractAll(msgBuf, recvCount);
else if (strcmp(message,"*") == 0) result = MultiplyAll(msgBuf, recvCount);
char resStr[10];
itoa(result,resStr,10);
printf("send result\n");
send(hClntSock, resStr, strlen(resStr), 0);
closesocket(hClntSock);
}
closesocket(hServSock);
WSACleanup();
return 0;
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
계산기 서버
#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\n", message);
}
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
계산기 클라

책은 클라에서 미리 연산자까지의 숫자 개수를 보내주는 식으로 구현함.
read()로 읽기 전의 데이터들은 입력 버퍼에 대기한다.
write()를 호출하면 데이터 수신 전 출력 버퍼에 대기한다.
Q. 입력 버퍼의 크기를 넘어서는 데이터가 전송되면?
TCP에는 슬라이딩 윈도우라는 프로토콜이 존재한다.
이것은 입력 버퍼의 크기를 초과하는 데이터 전송을 막아준다.
상대 소켓과의 연결
SEQ: 2000, ACK : 1001 같은 식으로 패킷에 번호를 붙인다상대 소켓과의 데이터 송수신
SEQ 1200, 100 byte data → ACK 1301 (패킷 번호 1200에 데이터 크기 100 + 1) → SEQ 1301 data ...상대 소켓과의 연결 종료
p.40 ~ 58
Project GNC 레포 이어받아서 Project FDS