#console tcp server ,client

 

f_ser.cs
0.00MB
f_cli.cs
0.00MB

#거래소 & Koscom 데이타를 보내는쪽은 Nagle 알고리즘을 적용한다.
#거래소 & Koscom 데이타를 보내는쪽은 Nagle 알고리즘을 적용한다.

#거래소 & Koscom
데이타를 송신하는부분에서
#send(102 byte)
#send(102 byte)
#send(102 byte)
#send(102 byte)
#send(102 byte)

#거래소 & Koscom 데이타를 수신하는쪽은
#recv = 102 * 1 byte
#recv = 102 * 4 byte
임을 보인다.

혹시라도, #거래소 & Koscom 데이타를 보내는쪽에서 Nagle 알고리즘을 적용하지 않는다면
비고) 송신하는 프로그램에서 다음의 코드를 추가하면, Nagle 알고리즘을 적용하지 않는다.
#include<netinet/tcp.h>
char on=1;
if(setsockopt(sock,OPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on))<0) printf("error!!\n");

#거래소 & Koscom데이타를 송신하는부분에서
#send(102 byte)
#send(102 byte)
#send(102 byte)
#send(102 byte)
#send(102 byte)

#거래소 & Koscom데이타를 수신하는쪽은
#recv = 102 byte
#recv = 102 byte
#recv = 102 byte
#recv = 102 byte
#recv = 102 byte
임을 보인다. 

#Nagle 알고리즘에 대해서 알아본다.

Nagle알고리즘? 네트워크 상에 패킷의 수를 줄이기 위해 개발된 알고리즘

1. 일반 네트워크 통신방법
- 일반적인 통신알고리즘은 데이터는 패킷으로 만들어 보낸다는 것이며 수신호스트는 이에 대한 ACK를 보낸다는 것입니다. 
예를 들어, A,B 두 호스트가 통신을 합니다. A는 B에게 'Nagle'라는 데이터를 보내기 원하면, 
먼저 'N'이라는 데이터를 패킷으로 만들어 출력버퍼로 보냅니다. 
그리고 ACK를 받고 안받고 관계없이 'a'를 패킷으로 만들어 보내고 이어서 'g', 'l', 'e' 각 데이터를 패킷으로 만들어 보낼 것입니다. 
수신호스트로부터의 ACK가 언제 오는가는 전혀 관계가 없고, 언제 오든지 오기만 하면 되는 것입니다.

2. Nagle 알고리즘
- 네트웍에서 Nagle 알고리즘은 "가능하면 조금씩 여러 번 보내지 말고 한번에 많이 보내라(Effective TCP)" 라는 원칙을 기반으로 만들어진 알고리즘입니다.
- Nagle 알고리즘의 원리는 ACK를 받은 다음에 데이터를 보내고 ACK를 받을 때까지 출력버퍼의 데이터를 저장하였다가 ACK를 받으면 버퍼의 데이터를 모두 패킷으로 만들어 보낸다는 것입니다. 
예를 들어 A가 'N'이라는 데이터를 패킷으로 만들어 보내고, 계속해서 다음 데이터를 보내는 것이 아니라 출력버퍼로 보내어 저장시켜 둡니다. 
그러다가 ACK가 오면 출력버퍼에 저장된 'agle'라는 데이터를 보냅니다.

 

 

- TCP 소켓은 Default로 Nagle 알고리즘을 적용하고 있습니다.

3. Nagle 알고리즘의 장단점
  - 장점 : 네트워크의 효율성이 높아짐. (똑같은 데이터를 보내더라도 생산하는 패킷이 적음)
  - 단점 : 송신 호스트가 ACK를 받을 때까지 기다려야 하므로 전송 속도가 느려짐

4. Nagle 알고리즘의 중단
  - 몇몇 네트웍 관련 프로그램에서는 네트웍의 전송량이나 부하보다는 빠른 응답속도를 더 중요시 여기는 상황이 있습니다. 
  그러한 때에는 TCP_NODELAY  라는 옵션을 사용하여 Nagle 알고리즘을 제거 할 수 있습니다.
  - TCP_NODELAY 옵션이
     1(TRUE) : Nagle 알고리즘을 적용하지 않습니다.
     2(FALSE): Nagle 알고리즘을 적용합니다.

int opt_val = TRUE;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, sizeof(opt_val));

해당 옵션의 사용은 네트웍 부하를 극대화 시켜주면서 서버의 전체적인 성능을 무척 감소하기때문에 꼭 필요한 경우에만 매우 주의를 해서 사용해야 합니다.
- 전송은 작은 단위로 자주 이루어지지만 즉각적인 응답은 필요 없는 어플리케이션에서만 사용 되어야 합니다.(마우스 움직임 같은)
- Nagle 알고리즘은 리얼타임시스템에서의 제어와 특히나 인터렉티브한 키 입력을 하는 어플리케이션에서는 안 좋은 영향을 미칩니다. 
선택적으로 Nagle 알고리즘을 통과하는 한가지 방법은 Out-of-bind 메시지 시스템을 쓰는 것입니다. 
그러나 이것은 내용물에 제약이 있고 또 다른 문제(순서의 상실: loss of sequentiality)를 일으킬 수 있습니다.

#거래소 & Koscom tcp 데이타를 서버에서 받을때에 모습(송신쪽에서 Nagle On일경우)

 

#거래소 & Koscom tcp 데이타를 서버에서 받을때에 모습(송신쪽에서 Nagle Off일경우)

소스파트)
int sd, ret, on=1,off=0, sz_sbuf;

/* added to options of socket by Changseop Oh from CheongJo */

/* Now >>>> nagle off -----------------*/
/* Now >>>> nagle off -----------------*/
/* Now >>>> nagle off -----------------*/
if(setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(char*)&off,sizeof(on))<0)
sprintf(ebuf, "setsockopt() : REUSEADDR setting Error!");

#FTP server/client standard tcp program

 

fss_client.c
0.00MB
fss_server.c
0.00MB

 

 

NOT fork

NOT thread

NOT select

STANDARD tcp OK

 

 

비고) 클라이언트소스에 <sys/sendfile.h>에 선언되어진 sendfile 이라는 함수가 유용하게 사용된다.

RcvManualData.c
0.02MB
packet.h
0.00MB

 

마지막이 0xff로 끝나는,ㅡㅡ 데이타를 수신할경우에,ㅡㅡㅡㅡㅡㅡㅡㅡ
while(1)
{
    csock = accept();
    while(1)
    {
        recv_len = recv( csock, tmp, sizeof(tmp), 0);
        if(recv_len > 0)
        {
            for(ii=0; ii<recv_len; ii++)
            {
                data[data_len++ ] = tmp[ii];
                if(data_len > 2 && (unsifned char)data[data_len - 1] == (unsigned char)0xff)
                {
                    fprintf(stderr, "%.*s\n", data_len, data);
                    data_len = 0;
                    memset(data, 0x00, sizeof(data));
                }
           }
       }
        else break;
    }
    close(csock);
}

recv_handler.c
0.00MB

fss_send.c
0.00MB

 

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <string.h>

 

#define MAXLINE 9999
#define MAX_SOCK 128

 

int main(int argc, char *argv[]) 
{
FILE *fp=NULL;

char line[MAXLINE], message[MAXLINE+1], filename[MAXLINE+1];
struct sockaddr_in server_addr;
int maxfdp1;
int ____socket; /* 서버와 연결된 소켓번호 */
fd_set read_fds;

int kk=0;

 

if (argc != 4) {

printf("Usage : %s server_ip port filename\n", argv[0]);

printf("%s 127.0.0.1 12572 /usr2/suksu/ftp/BATCH_A0011.dat\n", argv[0]);

exit(0);
}

 

sprintf(filename, "%s", argv[3]);
if((fp=fopen(filename, "rt"))==NULL) exit(0);

/* 소켓 생성 */
if ((____socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("Client: Can't open stream socket.\n");
exit(0);
}

 

/* 채팅 서버의 소켓주소 구조체 server_addr 초기화 */
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(atoi(argv[2]));

/* 연결요청 */
if (connect(____socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
printf("Client: Can't connect to server.\n");
exit(0);

else 
{
    printf("Connected with server succ!!\n");
}

while (1) 
{
memset(line,0x00,sizeof(line));
if(fgets(line,sizeof(line),fp)==NULL) break;

line[strlen(line)-1]=0x00;

if (send(____socket, line, strlen(line), 0) < 0) 
{
printf("Client: Write error on socket.\n");
break;
}
//printf("%s\n", line);

usleep(4444);
kk++;
}

close(____socket);
if(fp != NULL) fclose(fp);

printf("FileName[%s] :[%05d]\n", filename, kk);
}

 

 

 

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <string.h>

#define MAXLINE 99999
#define MAX_SOCK 64

int getmax(int);
void disconnect_client(int); /* 채팅 탈퇴 처리 함수 */
void my_signal(int signo); /* 새로운 시그널 처리 함수 선언 */

int maxfdp1;            /* 최대 소켓번호+1 */
int num_chat = 0;       /* 채팅 참가자 수 */
int ____main_socket;                  /* 초기 소켓 */
int ____client_socket[MAX_SOCK]; /* 채팅에 참가자 소켓번호 목록 */

int main(int argc, char *argv[]) 
{
char rline[MAXLINE+1];
int i, j, kk;
int recv_len;
int client_fd, clilen;

int recv_len_sum=0;
int recv_seq_sum=0;
int recv_divide;


fd_set read_fds; /* 일기 감지할 소켓번호 구조체 */
struct sockaddr_in client_addr, server_addr;

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

/* 초기소켓 생성 */
if ((____main_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("Server: Can't open stream socket.");
exit(0);
}

/* server_addr 구조체의 내용 세팅 */
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(atoi(argv[1]));

if (bind(____main_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
printf("Server: Can't bind local address.\n");
exit(0);
}

if (signal(SIGINT, my_signal) == SIG_ERR) { /* Ctrl+C */
printf("Server: signal(SIGINT) error\n");
exit(0);
}
if (signal(SIGTERM, my_signal) == SIG_ERR) { /* software termination */
printf("Server: signal(SIGTERM) error\n");
exit(0);
}
if (signal(SIGQUIT, my_signal) == SIG_ERR) { /* Ctrl+\ */
printf("Server: signal(SIGQUIT) error\n");
exit(0);
}


/* 클라이언트로부터 연결요청을 기다림 */
listen(____main_socket, 5); /* backlog = 5 */

maxfdp1 = ____main_socket + 1; /* 최대 소켓번호+1 */

while (1) 
{
FD_ZERO(&read_fds);
FD_SET(____main_socket, &read_fds);
for (kk=0; kk < num_chat; kk++)
{
    FD_SET(____client_socket[kk], &read_fds);
}

maxfdp1 = getmax(____main_socket) + 1; /* maxfdp1 재 계산 */

if (select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) {
printf("Server: select error <= 0\n");
break;
}

if (FD_ISSET(____main_socket, &read_fds)) 
{
clilen = sizeof(client_addr);
client_fd = accept(____main_socket, (struct sockaddr *)&client_addr, &clilen);
if (client_fd == -1) 
{
    printf("Server: accept error\n");
    break;
    }

    ____client_socket[num_chat] = client_fd;
    num_chat++;
}

for (kk=0; kk < num_chat; kk++) 
{
if (FD_ISSET(____client_socket[kk], &read_fds)) 
{
if ((recv_len = recv(____client_socket[kk], rline, MAXLINE, 0)) <= 0) 
{
disconnect_client(kk); /* abrupt exit */
continue;
}
rline[recv_len] = '\0';

            recv_divide = recv_len / getfromframeid(rline, recv_len);
recv_seq_sum++;
recv_len_sum = recv_len_sum + recv_divide;

printf("SESSION SEQ[%07d]/RECV LENGTH[%07d]/DIVIDE[%07d]/REAL SUM[%07d]/SEQ SUM[%07d]\n", 
                                        kk+1, recv_len,
recv_divide, recv_len_sum, recv_seq_sum);
}
}
} /* while */
my_signal(SIGIO);
}

/* 채팅 탈퇴 처리 */
void disconnect_client(int i) {
struct sockaddr_in client_addr;

close(____client_socket[i]);
if (i != num_chat-1)
____client_socket[i] = ____client_socket[num_chat-1];
num_chat--;

printf("[function]disconnect_client>>[%d]\n", num_chat);
}

/* ____client_socket[] 내의 최대 소켓번호 얻기(초기치는 k) */
int getmax(int k) {
int max = k;
int r;
for (r=0; r < num_chat; r++)
if (____client_socket[r] > max)
max = ____client_socket[r];
return max;
}

/* 시그널 처리 함수 정의 */
void my_signal(int signo) {
int i;

signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);

/* 모든 열려있는 소켓을 닫는다 */
close(____main_socket);
for (i=0; i < num_chat; i++)
close(____client_socket[i]);

exit(0);
}

int getfromframeid(char *tmp, int len)
{
int kk=0;

if(memcmp(tmp, "A0011", 5) == 0) kk=800;

return kk;
}


/*

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

gcc -o w_send w_send.c -lwsock32 -Wall -DTEST_PRINTF

*/

 

#include  <WinSock2.h>
#include  <windows.h>
#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>
#include  <time.h>

#define  MAXLINE 4096

DWORD WINAPI stdin_input_send_thread(LPVOID arg);

FILE *fp=NULL;
FILE *stream=NULL;
char line[MAXLINE], chatdata[MAXLINE+1];

struct sockaddr_in server_addr;
SOCKET clientsocket; //server connect socket
char *escape = "quit"; //exit command message
BOOL bisquit;           //exit falg variable

int main(int argc, char *argv[])
{
    WSADATA wsa;    //socket
    HANDLE hthread; //thread
    DWORD threadid;
    int size;

    if (argc != 4) 
    {
        printf("usage : %s server_address port filename\n", argv[0]);
        return(-1);
    }
    bisquit = FALSE;

    //socket initialization
    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) 
    {
        return(-2);
    }
    //socket creation
    if ((clientsocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    {
        printf("fail make socket\n");
        return(-3);
    }

    //memory initialization
    memset(&server_addr, 0x00, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    //connection with server
    if (connect(clientsocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
    {
        printf("fail connect to server\n");
        return(-4);
    }

    if((fp = fopen(argv[3], "rt"))==NULL)
    {
        printf("fopen error(%s)\n", argv[3]);
        return(-5);
    }

if((stream = fopen("KRX_SEND.dat", "wt"))==NULL)
    {
        printf("fopen error(%s)\n", argv[3]);
        return(-5);
    }

    hthread = CreateThread(NULL, 0, stdin_input_send_thread, 0, 0, &threadid);
    if (hthread == NULL) 
    {
        printf("fail make thread\n");
    }
    else 
    {
        CloseHandle(hthread);
    }

    while (!bisquit) 
    {
        memset(chatdata, 0x00, sizeof(chatdata));

        if ((size = recv(clientsocket, chatdata, MAXLINE, 0)) == INVALID_SOCKET) 
        {
            break;
        }
        else 
        {
            chatdata[size] = '\0';
            printf("(RECV)%s", chatdata);
fprintf(stream, "%s", chatdata);
        }
    }
    closesocket(clientsocket);
    WSACleanup();

    if(fp != NULL) fclose(fp);
if(stream != NULL) fclose(stream);

    return(0);
}

//user data input mechanism
DWORD WINAPI stdin_input_send_thread(LPVOID arg)
{
    char rbuf[MAXLINE];

    while(TRUE) 
    {
        memset(rbuf, 0x00, sizeof(rbuf));
        if(fgets(rbuf, sizeof(rbuf), fp) == NULL)
{
bisquit = TRUE;
break;
}

        printf("(SEND)%s", rbuf);

        if (send(clientsocket, rbuf, strlen(rbuf), 0) < 0) 
        {
            return(-2);
        }

        Sleep(50); //#include
    }

closesocket(clientsocket);
    return 0;
}

+ Recent posts