입출력과 소켓

이동욱

2021/08/17

Categories: 네트워크

입출력 전반


파일 디스크립터, 파일 테이블, 파일


파일 디스크립터 테이블과 열린 파일 테이블의 엔트리(Entry)


int dup(int oldfd);
결과값 : 복사된 파일 디스크립터(새로 부여된 디스크립터)
int dup2(int oldfd, int newfd);

결과값 : 복사된 파일 디스크립터 (새로 부여된 디스크립터)

파일 오프셋이란?


#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

인자

결과값

예제

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  int fd1, fd2, fd3;
  char buff[BUFSIZ];
  int read_len, n_write;
  if (argc != 2) {
    printf("usage: %s filename \n", argv[0]);
    return -1;
  }

  fd1 = open(argv[1], O_RDWR | O_CREAT | O_TRUNC);
  fd2 = open(argv[1], O_RDONLY);
  fd3 = dup(fd1);

  fgets(buff, BUFSIZ - 1, stdin);

  read_len = strlen(buff);
  n_write = write(fd1, "abc", 3);
  n_write += write(fd1, buff, read_len + 1);
  if (n_write == -1) printf("error");

  printf("offset (fd1): %d\n", (int) lseek(fd1, 0, SEEK_CUR));
  printf("offset (fd2): %d\n", (int) lseek(fd2, 0, SEEK_CUR));
  printf("offset (fd3): %d\n", (int) lseek(fd3, 0, SEEK_CUR));

  read(fd2, buff, 4);
  write(1, buff, 4);

  printf("-----\n");

  printf("offset (fd1): %d\n", (int) lseek(fd1, 0, SEEK_CUR));
  printf("offset (fd2): %d\n", (int) lseek(fd2, 0, SEEK_CUR));
  printf("offset (fd3): %d\n", (int) lseek(fd3, 0, SEEK_CUR));

  close(fd1);
  fgets(buff, BUFSIZ - 1, stdin);
  read_len = strlen(buff);
  n_write += write(fd3, buff, read_len);

  lseek(fd2, 0, SEEK_SET);
  memset(buff, 0, BUFSIZ);
  read_len = read(fd2, buff, n_write);
  write(1, buff, n_write);
  close(fd2);
  close(fd3);
  return 0;
}

소켓 전용 입출력 함수


ssize_t send(int socket, const void *buffer, size_t length, int flags);

인자

ssize_t recv(int socket, void *buffer, size_t length, int flags);

인자

flags

Urgent 데이터

“전송하는 데이터 중에서 긴급한 메시지가 있으니, 이 부분을 확인하시오.”

예제

클라이언트 프로그램

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  int connect_sd;
  struct sockaddr_in client_addr;
  int client_addr_len, read_len;
  char write_buffer[BUFSIZ];

  if (argc != 3) {
    printf("usage: %s <IP Address> <Port Number>\n", argv[0]);
    return -1;
  }

  connect_sd = socket(PF_INET, SOCK_STREAM, 0);

  printf("=== client program ===\n");

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

  connect(connect_sd, (struct sockaddr *) &client_addr, sizeof(client_addr));

  send(connect_sd, "normal_msg1", strlen("normal_msg1"), 0);
  send(connect_sd, "normal_msg2", strlen("normal_msg2"), 0);
  send(connect_sd, "urgent_msg", strlen("urgent msg"), MSG_OOB);
  send(connect_sd, "normal_msg3", strlen("normal_msg3"), 0);
  close(connect_sd);

  return 0;
}

서버 프로그램

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>

int listen_sd, connect_sd;

void urgent_handler(int sig);

int main(int argc, char *argv[]) {
  struct sockaddr_in server_addr, client_addr;
  int client_addr_len, read_len, str_len, state;
  char read_buffer[BUFSIZ];
  pid_t pid;
  struct sigaction act;

  if (argc != 2) {
    printf("usage: %s [port number]\n", argv[0]);
    return -1;
  }

  act.sa_handler = urgent_handler;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;

  printf("server start...\n");
  listen_sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

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

  bind(listen_sd, (struct sockaddr *) &server_addr, sizeof(server_addr));
  listen(listen_sd, 5);

  client_addr_len = sizeof(client_addr);
  connect_sd = accept(listen_sd, (struct sockaddr *) &client_addr, &client_addr_len);
  fprintf(stderr, "a client is connected...\n");

  fcntl(connect_sd, F_SETOWN, getpid());
  state = sigaction(SIGURG, &act, 0);

  while (1) {
    read_len = recv(connect_sd, read_buffer, sizeof(read_buffer), 0);
    read_buffer[read_len] = '\0';
    printf("client: %s\n", read_buffer);
    if (read_len == 0) {
      close(connect_sd);
      break;
    }
  }
  fprintf(stderr, "the client is disconnected.\n");
  close(listen_sd);
  return 0;
}

void urgent_handler(int sig) {
  int read_len;
  char read_buffer[BUFSIZ];

  read_len = recv(connect_sd, read_buffer, sizeof(read_buffer), MSG_OOB);
  read_buffer[read_len] = '\0';
  printf("client(urgent): %s\n", read_buffer);
}

표준 입출력 함수


  • 사용자 A는 100 바이트를 작성하는 write() 함수를 한 번 호출하여 100 바이트를 작성한다.
  • 사용자 B는 10 바이트를 작성하는 write() 함수를 10번 호출하여 100 바이트를 작성한다.

스트림

FILE *fp;

fp = fopen("filename.txt", "r");
...
fprintffp, "....");
....
fclose(fp);
FILE *fdopen(int fd, const char *mode);
int fileno(FILE *stream)

표준 입출력 버퍼 관리

int fflush(FILE *stream);
void setbuff(FILE *stream, char *buf);

예제 - 표준 입출력 함수를 이용한 소켓 프로그래밍

클라이언트

nclude <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
  int connect_sd;
  struct sockaddr_in client_addr;
  int client_addr_len, read_len;
  char write_buffer[BUFSIZ];
  FILE *wfp;

  if (argc != 3) {
    printf("usage: %s <IP Address> <Port Number>\n", argv[0]);
    return -1;
  }

  connect_sd = socket(PF_INET, SOCK_STREAM, 0);
  printf("=== client program ===\n");

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

  connect(connect_sd, (struct sockaddr *)&client_addr, sizeof(client_addr));
  wfp = fdopen(connect_sd, "w");
  while (1) {
    printf("send msg: ");
    fgets(write_buffer, BUFSIZ, stdin);
    fputs(write_buffer, wfp);
    fflush(wfp);
    if (!strcmp(write_buffer, "END\n")) break;
  }
  fclose(wfp);
  return 0;
}

서버

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

int main(int argc, char *argv[]) {
  int listen_sd, connect_sd;
  struct sockaddr_in server_addr, client_addr;
  int client_addr_len, read_len, str_len, state;

  char read_buffer[BUFSIZ];
  FILE *rfp;

  if (argc != 2) {
    printf("usage %s [port number]\n", argv[0]);
    return -1;
  }

  printf("server start...\n");
  listen_sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

  memset(&server_addr, 0, sizeof(server_addr));

  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(atoi(argv[1]));

  bind(listen_sd, (struct sockaddr *)&server_addr, sizeof(server_addr));
  listen(listen_sd, 5);

  client_addr_len = sizeof(client_addr);

  connect_sd = accept(listen_sd, (struct sockaddr*)&client_addr, &client_addr_len);
  fprintf(stderr, "a client is connected...\n");

  rfp = fdopen(connect_sd, "r");

  while (!feof(rfp)) {
    fgets(read_buffer, BUFSIZ, rfp);
    printf("%s", read_buffer);
  }
  fprintf(stderr, "the client is disconnected. \n");
  fclose(rfp);
  return 0;
}

참고 문헌


>> Home