如何关闭对write()系统调用的缓冲? [英] How to turn off buffering on write() system call?

查看:197
本文介绍了如何关闭对write()系统调用的缓冲?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我常想,的write()系统调用是缓冲和 FWRITE FREAD 用于缓冲的IO。但是我写的简单程序,建立一些缓冲仍在继续使用写入时()。我使用的write()阅读()上的插座。由于缓冲,能够为客户端落后而服务器保持发送数据包。我不要那个。我想服务器发送更多的记录之前,客户必须消耗记录。

我怎样才能做到这一点无需添加确认等网络负荷!

我在Linux上使用的gcc

server.c:

 的#include<&stdio.h中GT;
#包括LT&;&errno.h中GT;
#包括LT&; SYS / socket.h中>
#包括LT&; ARPA / inet.h>
#包括LT&;&stdio.h中GT;
#包括LT&; netinet / in.h中>
#包括LT&;&string.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&; netinet / tcp.h中>INT remote_rr_port = 2000; //服务器将发送使用此端口上连接R​​R日志。
字符常量* remote_server_ip =127.0.0.1;
INT connFD_rr;
静态无效startTcpServer为(int * SD,const int的端口){
  * SD =插座(AF_INET,SOCK_STREAM,0);  //设置套接字选项,以便端口可以被重用
  INT启用= 1;
  setsockopt的(* SD,SOL_SOCKET,SO_REUSEADDR,&安培;启用的sizeof(INT));
  结构有sockaddr_in一个;
  memset的(&放大器;一,0,sizeof的(一));
  a.sin_family = AF_INET;
  a.sin_port =口;
  a.sin_addr.s_addr = INADDR_ANY;
  INT bindResult =绑定(* SD(结构sockaddr *)及一,的sizeof(一));
  听(* SD,2);
}
//等待来自客户端的连接
静态INT getTcpConnection(INT SD){
  焦炭BUF [100];
  socklen_t的LEN;
  结构SOCKADDR_IN clientAddress;
  的printf(\\ nWaiting从远程客户端\\ n连接);
  LEN = sizeof的(clientAddress);
  INT connFD =接受(SD,(结构sockaddr *)及clientAddress,和放大器; LEN);
  setsockopt的(connFD_rr,SOL_SOCKET,SO_SNDBUF(INT []){0},的sizeof(INT));
  的printf(%S:从\\ n连接%d个\\ N,inet_ntop(AF_INET,&安培; clientAddress.sin_addr,BUF,sizeof的(BUF)),clientAddress.sin_port);
  fflush(标准输出);
  返回connFD;
}FILE * rdrr_server_start(无效){  //套接字描述符的两个连接
  INT rr_sd;
  INT input_sd;  startTcpServer(安培; rr_sd,remote_rr_port);  connFD_rr = getTcpConnection(rr_sd);  返回fdopen(connFD_rr,W);
}诠释主(){
  INT I = 0;
  rdrr_server_start();  对于(i = 0; I<千万,我++){
    写(connFD_rr,和放大器;我的sizeof(INT));
    的printf(%d个\\ N,I);
  }
  返回0;
}

client.c:

 的#include< SYS / socket.h中>
#包括LT&; ARPA / inet.h>
#包括LT&;&stdio.h中GT;
#包括LT&; netinet / in.h中>
#包括LT&;&string.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&; netinet / tcp.h中>INT remote_rr_port = 2000; //服务器将发送使用此端口上连接R​​R日志。
字符常量* remote_server_ip =127.0.0.1;
INT connFD_rr;FILE * rdrr_client_start(无效){  connFD_rr =插座(AF_INET,SOCK_STREAM,0);  结构有sockaddr_in一个;
  memset的(&放大器;一,0,sizeof的(一));
  a.sin_family = AF_INET;
  a.sin_port = remote_rr_port;
  a.sin_addr.s_addr = inet_addr(remote_server_ip);  的printf(\\ nConnecting到RR端口上服务器);
  INT CONNECT_TO_SERVER =连接(connFD_rr,(结构sockaddr *)及一,的sizeof(一));
  的printf(\\ nConnected到RR端口上服务器);
  setsockopt的(connFD_rr,SOL_SOCKET,SO_RCVBUF,(INT []){0},的sizeof(INT));
  返回fdopen(connFD_rr,R);
}诠释主(){
  INT I = 0;
  rdrr_client_start();
  getrchar();
  而(1){
    阅读(connFD_rr,和放大器;我的sizeof(INT));
    的printf(%d个\\ N,I);
  }
  返回0;
}


解决方案

也许你的意思是,你要禁用的 Nagle算法的在这种情况下,解决方案是:

 的setsockopt(袜子,IPPROTO_TCP,TCP_NODELAY,(INT []){1},的sizeof(INT));

编辑:嗯,它看起来像你想比这更多,我怀疑你想要什么是可能的,而不在UDP上设计自己的协议

编辑2::您可以通过限制发送来获得类似于你想要的效果和接收缓冲区大小。服务器(发送方)应该做的:

 的setsockopt(袜子,SOL_SOCKET,SO_SNDBUF(INT []){} YOUR_BUF_LIMIT,sizeof的(INT));

和客户端(接收器)应该做的:

 的setsockopt(袜子,SOL_SOCKET,SO_RCVBUF,(INT []){} YOUR_BUF_LIMIT,sizeof的(INT));

I used to think that write() system call is unbuffered and that fwrite and fread are used for buffered IO. However I wrote simple programs to establish that some buffering was still going on when using write(). I am using write() and read() on sockets. Due to buffering, it is possible for the client to lag behind while server keeps sending packets. I do not want that. I want that the client must consume the record before the server sends more records.

How can I make that happen without adding network load of acknowledgments etc !

I am using gcc on linux

server.c :

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

int remote_rr_port=2000; // Server will send RR logs using connection on this port.
char const *remote_server_ip="127.0.0.1";
int connFD_rr;


static void startTcpServer(int *sd, const int port) {
  *sd= socket(AF_INET, SOCK_STREAM, 0);

  // Set socket option so that port can be reused
  int enable = 1;
  setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
  struct sockaddr_in a;
  memset(&a,0,sizeof(a));
  a.sin_family = AF_INET;
  a.sin_port = port;
  a.sin_addr.s_addr = INADDR_ANY;
  int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a));
  listen(*sd,2);
}


// Wait for connection from client
static int getTcpConnection(int sd) {
  char buf[100];
  socklen_t len;
  struct sockaddr_in clientAddress;
  printf("\nWaiting for connection from remote client\n");
  len = sizeof(clientAddress);
  int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len);
  setsockopt(connFD_rr, SOL_SOCKET, SO_SNDBUF, (int[]){0}, sizeof(int));
  printf("\n Connection from : %s:%d\n",inet_ntop(AF_INET, &clientAddress.sin_addr, buf, sizeof(buf)),clientAddress.sin_port);
  fflush(stdout);
  return connFD;
}

FILE* rdrr_server_start(void) {

  // Socket Descriptors for the two connections
  int rr_sd;
  int input_sd;

  startTcpServer(&rr_sd, remote_rr_port);

  connFD_rr = getTcpConnection(rr_sd);

  return fdopen(connFD_rr, "w");
}

int main() {
  int i = 0;
  rdrr_server_start();

  for(i=0;i<10000000; i++) {
    write(connFD_rr, &i, sizeof (int));
    printf("%d\n", i);
  }
  return 0;
}

client.c :

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



int remote_rr_port=2000; // Server will send RR logs using connection on this port.
char const *remote_server_ip="127.0.0.1";
int connFD_rr;

FILE* rdrr_client_start(void) {

  connFD_rr = socket(AF_INET, SOCK_STREAM, 0);

  struct sockaddr_in a;
  memset(&a,0,sizeof(a));
  a.sin_family = AF_INET;
  a.sin_port = remote_rr_port;
  a.sin_addr.s_addr = inet_addr(remote_server_ip);

  printf("\nConnecting to Server on RR port");
  int CONNECT_TO_SERVER= connect(connFD_rr,(struct sockaddr *)  &a, sizeof(a));
  printf("\nConnected to server on RR port");
  setsockopt(connFD_rr, SOL_SOCKET, SO_RCVBUF, (int[]){0}, sizeof(int));
  return fdopen(connFD_rr, "r");
}  

int main() {
  int i = 0;
  rdrr_client_start();
  getrchar();
  while(1) {
    read(connFD_rr, &i, sizeof (int));
    printf("%d\n", i);
  }
  return 0;
} 

解决方案

Perhaps what you mean is that you want to disable Nagle's Algorithm in which case the solution is:

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (int[]){1}, sizeof(int));

Edit: Hmm, it looks like you want more than this, and I doubt what you want is possible without designing your own protocol on top of UDP.

Edit 2: You may be able to get an effect similar to what you want by limiting the send and receive buffer sizes. The server (sender) should do:

setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (int[]){YOUR_BUF_LIMIT}, sizeof(int));

and the client (receiver) should do:

setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (int[]){YOUR_BUF_LIMIT}, sizeof(int));

这篇关于如何关闭对write()系统调用的缓冲?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆