TCP/IP网络编程——基于标准IO的回声客户端

echo_stdserv.c

//套接字的标准IO:标准IO函数有自己的缓冲,可以提高传输性能
//而系统函数read和write未提供缓冲,传输相对较慢
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[])
{
  int serv_sock;
  int clnt_sock;
  
  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  socklen_t clnt_addr_size;
  int str_len;
  char message[BUF_SIZE];
  
  FILE *readfp;
  FILE *writefp;
  
  if(argc!=2)
  {
    exit(1);
  }
  
  //TCP socket
  serv_sock=socket(PF_INET, SOCK_STREAM, 0);
  if(serv_sock == -1)
    error_handling("socket error!");
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;	//IPV4协议族
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//主机字节序(host)转换成网络字节序(net)(大端序)
  serv_addr.sin_port = htons(atoi(argv[1]));	//端口号

  if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind error");

  if(listen(serv_sock, 5) == -1)
    error_handling("listen error");

  clnt_addr_size = sizeof(clnt_addr);
  
  int i;
  for(i=0;i<5;i++)
  {
    clnt_sock=accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);
    if(clnt_sock == -1)
      error_handling("accept error");
    else
      printf("connect client: %d \n", i+1);
    
    //下面使用标准IO函数传输数据
    readfp=fdopen(clnt_sock, "r");	//将套接字描述符转换为FILE指针
    writefp=fdopen(clnt_sock, "w");
    while(!feof(readfp))
    {
      fgets(message, BUF_SIZE, readfp);
      fputs(message, writefp);
      //标准IO内部有额外缓冲,若不调用fflush则无法立即将数据传输到客户端
      fflush(writefp);
    }
    fclose(readfp);
    fclose(writefp);
  }
  
  close(serv_sock);
  return 0;
}

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

IO流分离(半关闭的实现)

sep_serv.c

//分离IO流,文件描述符的复制和半关闭
//文件描述符复制:dup(),dup2()
//shutdown函数使服务器端进入半关闭状态
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[])
{
  int serv_sock;
  int clnt_sock;
  
  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  socklen_t clnt_addr_size;
  int str_len;
  char buf[BUF_SIZE];
  
  FILE *readfp;
  FILE *writefp;
  
  if(argc!=2)
  {
    exit(1);
  }
  
  //TCP socket
  serv_sock=socket(PF_INET, SOCK_STREAM, 0);
  if(serv_sock == -1)
    error_handling("socket error!");
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;	//IPV4协议族
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//主机字节序(host)转换成网络字节序(net)(大端序)
  serv_addr.sin_port = htons(atoi(argv[1]));	//端口号

  if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind error");

  if(listen(serv_sock, 5) == -1)
    error_handling("listen error");

  clnt_addr_size = sizeof(clnt_addr);
  
  readfp=fdopen(clnt_sock, "r");
  writefp=fdopen(dup(clnt_sock), "w");	//使用dup复制套接字描述符
  
  fputs("hello world!", writefp);
  fflush(writefp);
  
  //调用shutdown关闭输出流,fileno作用是将FILE指针转换为描述符
  shutdown(fileno(writefp), SHUT_WR);
  fclose(writefp);	//关闭writefp不会关闭整个套接字,因为上面复制了套接字描述符
  
  fgets(buf, sizeof(buf), readfp);
  fputs(buf, stdout);
  
  fclose(readfp);	//至此关闭了套接字
  return 0;
}

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

猜你喜欢

转载自blog.csdn.net/u012411498/article/details/80508362
今日推荐