Linux下怎么实现TCP使用服务器端游标在接收到信息以后,自动返回一个值给客户端

C语言学习之Linux下TCP服务器与客户端的实现
客户端代码如下:
#define portnumber 3333
int main(int argc, char *argv[])
char buffer[1024];
struct sockaddr_in server_
struct hostent *
/* 使用hostname查询host 名字 */
if(argc!=2)
fprintf(stderr,"Usage:%s hostname \a\n",argv[0]);
if((host=gethostbyname(argv[1]))==NULL)
fprintf(stderr,"Gethostname error\n");
/* 客户程序开始建立 sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:ISOCK_STREAM:TCP
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr)); // 初始化,置0
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
// (将本机器上的short数据转化为网络上的short数据)端口号
server_addr.sin_addr=*((struct in_addr *)host->h_addr); // IP地址
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
/* 连接成功了 */
printf("Please input char:\n");
/* 发送数据 */
fgets(buffer,1024,stdin);
send(sockfd,buffer,strlen(buffer),0);
/* 结束通讯 */
close(sockfd);
服务器代码如下:
#define portnumber 3333//服务器的端口号和客户端的端口号一定相等
int main(int argc, char *argv[])
int sockfd,new_
struct sockaddr_in server_
struct sockaddr_in client_
char buffer[1024];
/* 服务器端开始建立sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:IPV4;SOCK_STREAM:TCP
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in)); // 初始化,置0
server_addr.sin_family=AF_INET;
// Internet
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
// (将本机器上的long数据转化为网络上的long数据)和任何主机通信
//INADDR_ANY 表示可以接收任意IP地址的数据,即绑定到所有的IP
server_addr.sin_port=htons(portnumber);
// (将本机器上的short数据转化为网络上的short数据)端口号
/* 捆绑sockfd描述符到IP地址 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
/* 设置允许连接的最大客户端数 */
if(listen(sockfd,5)==-1)
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
/* 服务器阻塞,直到客户程序建立连接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); // 将网络地址转换成.字符串
//if((nbytes=read(new_fd,buffer,1024))==-1) //此处可以写为if((nbytes=recv(new_fd,buffer,1024,0))==-1)
if((nbytes=recv(new_fd,buffer,1024,0))==-1)
fprintf(stderr,"Read Error:%s\n",strerror(errno));
buffer[nbytes]='\0';
printf("Server received %s\n",buffer);
/* 这个通讯已经结束 */
close(new_fd);
/* 循环下一个 */
/* 结束通讯 */
close(sockfd);
博客访问: 881760
博文数量: 146
博客积分: 65
博客等级: 民兵
技术积分: 3334
注册时间:
互联网行业新兵
分类: LINUX 10:22:36
原文地址: 作者:
本篇我们用一个测试机上的阻塞socket实例来说明主题。文章中所有图都是在测试系统上现截取的。
需要理解的3个概念
1. TCP socket的buffer
每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的流量(拥塞)控制便是依赖于这两个独立的buffer以及buffer的填充状态。接收缓冲区把数据缓存入内核,应用进程一直没有调用recv()进行读取的话,此数据会一直缓存在相应socket的接收缓冲区内。再啰嗦一点,不管进程是否调用recv()读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。recv()所做的工作,就是把内核缓冲区中的数据拷贝到应用层用户的buffer里面,并返回,仅此而已。进程调用send()发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回。换句话说,send()返回之时,数据不一定会发送到对端去(和write写文件有点类似),send()仅仅是把应用层buffer的数据拷贝进socket的内核发送buffer中,发送是TCP的事情,和send其实没有太大关系。接收缓冲区被TCP用来缓存网络上来的数据,一直保存到应用进程读走为止。对于TCP,如果应用进程一直没有读取,接收缓冲区满了之后,发生的动作是:收端通知发端,接收窗口关闭(win=0)。这个便是滑动窗口的实现。保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。
查看测试机的socket发送缓冲区大小,如图1所示
第一个值是一个限制值,socket发送缓存区的最少字节数;
第二个值是默认值;
第三个值是一个限制值,socket发送缓存区的最大字节数;
根据实际测试,发送缓冲区的尺寸在默认情况下的全局设置是16384字节,即16k。
在测试系统上,发送缓存默认值是16k。
proc文件系统下的值和sysctl中的值都是全局值,应用程序可根据需要在程序中使用setsockopt()对某个socket的发送缓冲区尺寸进行单独修改,详见文章《》,不过这都是题外话。
2. 接收窗口(滑动窗口)
TCP连接建立之时的收端的初始接受窗口大小是14600,细节如图2所示(129是收端,130是发端)
接收窗口是TCP中的滑动窗口,TCP的收端用这个接受窗口----win=14600,通知发端,我目前的接收能力是14600字节。
后续发送过程中,收端会不断的用ACK(ACK的全部作用请参照博文《》)通知发端自己的接收窗口的大小状态,如图3,而发端发送数据的量,就根据这个接收窗口的大小来确定,发端不会发送超过收端接收能力的数据量。这样就起到了一个流量控制的的作用。
21,22两个包都是收端发给发端的ACK包
第21个包,收端确认收到的前7240个字节数据,7241的意思是期望收到的包从7241号开始,序号加了1.同时,接收窗口从最初的14656(如图2)经过慢启动阶段增加到了现在的29120。用来表明现在收端可以接收29120个字节的数据,而发端看到这个窗口通告,在没有收到新的ACK的时候,发端可以向收端发送29120字节这么多数据。
第22个包,收端确认收到的前8688个字节数据,并通告自己的接收窗口继续增长为32000这么大。
3. 单个TCP的负载量和MSS的关系
MSS在以太网上通常大小是1460字节,而我们在后续发送过程中的单个TCP包的最大数据承载量是1448字节,这二者的关系可以参考博文《》。
实例详解send()
实例功能说明:接收端129作为客户端去连接发送端130,连接上之后并不调用recv()接收,而是sleep(1000),把进程暂停下来,不让进程接收数据。内核会缓存数据至接收缓冲区。发送端作为服务器接收TCP请求之后,立即用ret = send(sock,buf,70k,0);这个C语句,向接收端发送70k数据。
我们现在来观察这个过程。看看究竟发生了些什么事。wireshark抓包截图如下图4
图4说明,包序号等同于时序
1. 客户端sleep在recv()之前,目的是为了把数据压入接收缓冲区。服务端调用"ret = send(sock,buf,70k,0);"这个C语句,向接收端发送70k数据。由于发送缓冲区大小16k,send()无法将70k数据全部拷贝进发送缓冲区,故先拷贝16k进入发送缓冲区,下层发送缓冲区中有数据要发送,内核开始发送。上层send()在应用层处于阻塞状态;
2. 11号TCP包,发端从这儿开始向收端发送1448个字节的数据;
3. 12号TCP包,发端没有收到之前发送的1448个数据的ACK包,仍然继续向收端发送1448个字节的数据;
4. 13号TCP包,收端向发端发送1448字节的确认包,表明收端成功接收总共1448个字节。此时收端并未调用recv()读取,目前发送缓冲区中被压入1448字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;
5. 14号TCP包,收端向发端发送2896字节的确认包,表明收端成功接收总共2896个字节。此时收端并未调用recv()读取,目前发送缓冲区中被压入2896字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;
6. 15号TCP包,发端继续向收端发送1448个字节的数据;
7. 16号TCP包,收端向发端发送4344字节的确认包,表明收端成功接收总共4344个字节。此时收端并未调用recv()读取,目前发送缓冲区中被压入4344字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;
8. 从这儿开始,我略去很多包,过程类似上面过程。同时,由于不断的发送出去的数据被收端用ACK确认,发送缓冲区的空间被逐渐腾出空地,send()内部不断的把应用层buf中的数据向发送缓冲区拷贝,从而不断的发送,过程重复。70k数据并没有被完全送入内核,send()不管是否发送出去,send不管发送出去的是否被确认,send()只关心buf中的数据有没有被全部送往发送缓冲区。如果buf中的数据没有被全部送往发送缓冲区,send()在应用层阻塞,负责等待发送缓冲区中有空余空间的时候,逐步拷贝buf中的数据;如果buf中的数据被全部拷入发送缓冲区,send()立即返回。
9. 经过慢启动阶段接收窗口增大到稳定阶段,TCP吞吐量升高到稳定阶段,收端一直处于sleep状态,没有调用recv()把内核中接收缓冲区中的数据拷贝到应用层去,此时收端的接收缓冲区中被压入大量数据;
10. 66号、67号TCP数据包,发端继续向收端发送数据;
11. 68号TCP数据包,收端发送ACK包确认接收到的数据,ACK=62265表明收端已经收到62265字节的数据,这些数据目前被压在收端的接收缓冲区中。win=3456,比较之前的16号TCP包的win=23296,表明收端的窗口已经处于收缩状态,收端的接收缓冲区中的数据迟迟未被应用层读走,导致接收缓冲区空间吃紧,故收缩窗口,控制发送端的发送量,进行流量控制;
12. 69号、70号TCP数据包,发端在接收窗口允许的数据量的范围内,继续向收端发送2段1448字节长度的数据;
13. 71号TCP数据包,至此,收端已经成功接收65160字节的数据,全部被压在接收缓冲区之中,接收窗口继续收缩,尺寸为1600字节;
14. 72号TCP数据包,发端在接收窗口允许的数据量的范围内,继续向收端发送1448字节长度的数据;
15. 73号TCP数据包,至此,收端已经成功接收66609字节的数据,全部被压在接收缓冲区之中,接收窗口继续收缩,尺寸为192字节。
16. 74号TCP数据包,和我们这个例子没有关系,是别的应用发送的包;
17. 75号TCP数据包,发端在接收窗口允许的数据量的范围内,向收端发送192字节长度的数据;
18. 76号TCP数据包,至此,收端已经成功接收66609字节的数据,全部被压在接收缓冲区之中,win=0接收窗口关闭,接收缓冲区满,无法再接收任何数据;
19. 77号、78号、79号TCP数据包,由keepalive触发的数据包,响应的ACK持有接收窗口的状态win=0,另外,ACK=66801表明接收端的接收缓冲区中积压了66800字节的数据。
20. 从以上过程,我们应该熟悉了滑动窗口通告字段win所说明的问题,以及ACK确认数据等等。现在可得出一个结论,接收端的接收缓存尺寸应该是66800字节(此结论并非本篇主题)。
send()要发送的数据是70k,现在发出去了66800字节,发送缓存中还有16k,应用层剩余要拷贝进内核的数据量是N=70k-66800-16k。接收端仍处于sleep状态,无法recv()数据,这将导致接收缓冲区一直处于积压满的状态,窗口会一直通告0(win=0)。发送端在这样的状态下彻底无法发送数据了,send()的剩余数据无法继续拷贝进内核的发送缓冲区,最终导致send()被阻塞在应用层;
21. send()一直阻塞中。。。
图4和send()的关系说明完毕。
那什么时候send返回呢?有3种返回场景
send()返回场景
场景1,我们继续图4这个例子,不过这儿开始我们就跳出图4所示的过程了
22. 接收端sleep(1000)到时间了,进程被唤醒,代码片段如图5
随着进程不断的用"recv(fd,buf,2048,0);"将数据从内核的接收缓冲区拷贝至应用层的buf,在使用win=0关闭接收窗口之后,现在接收缓冲区又逐渐恢复了缓存的能力,这个条件下,收端会主动发送携带"win=n(n>0)"这样的ACK包去通告发送端接收窗口已打开;
23. 发端收到携带"win=n(n>0)"这样的ACK包之后,开始继续在窗口运行的数据量范围内发送数据。发送缓冲区的数据被发出;
24. 收端继续接收数据,并用ACK确认这些数据;
25. 发端收到ACK,可以清理出一些发送缓冲区空间,应用层send()的剩余数据又可以被不断的拷贝进内核的发送缓冲区;
26. 不断重复以上发送过程;
27. send()的70k数据全部进入内核,send()成功返回。
场景2,我们继续图4这个例子,不过这儿开始我们就跳出图4所示的过程了
22. 收端进程或者socket出现问题,给发端发送一个RST,请参考博文《》;
23. 内核收到RST,send返回-1。
场景3,和以上例子没关系
连接上之后,马上send(1k),这样,发送的数据肯定可以一次拷贝进入发送缓冲区,send()拷贝完数据立即成功返回。
send()发送结论
其实场景1和场景2说明一个问题
send()只是负责拷贝,拷贝完立即返回,不会等待发送和发送之后的ACK。如果socket出现问题,RST包被反馈回来。在RST包返回之时,如果send()还没有把数据全部放入内核或者发送出去,那么send()返回-1,errno被置错误值;如果RST包返回之时,send()已经返回,那么RST导致的错误会在下一次send()或者recv()调用的时候被立即返回。
场景3完全说明send()只要完成拷贝就成功返回,如果发送数据的过程中出现各种错误,下一次send()或者recv()调用的时候被立即返回。
概念上容易疑惑的地方
1. TCP协议本身是为了保证可靠传输,并不等于应用程序用tcp发送数据就一定是可靠的,必须要容错;
2. send()和recv()没有固定的对应关系,不定数目的send()可以触发不定数目的recv(),这话不专业,但是还是必须说一下,初学者容易疑惑;
3. 关键点,send()只负责拷贝,拷贝到内核就返回,我通篇在说拷贝完返回,很多文章中说send()在成功发送数据后返回,成功发送是说发出去的东西被ACK确认过。send()只拷贝,不会等ACK;
4. 此次send()调用所触发的程序错误,可能会在本次返回,也可能在下次调用网络IO函数的时候被返回。
实际上理解了阻塞式的,就能理解非阻塞的。
阅读(12720) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~
这篇文章写得有理有据,赞
请登录后评论。linux下socket通信,server和client简单例子 - 开源中国社区
当前访客身份:游客 [
当前位置:
发布于 日 18时,
linux socket 来自网络收集
代码片段(3)
1.&[代码]c代码 server部分&&&&
====================================================================
#include &netinet/in.h&
// for sockaddr_in
#include &sys/types.h&
// for socket
#include &sys/socket.h&
// for socket
#include &stdio.h&
// for printf
#include &stdlib.h&
// for exit
#include &string.h&
// for bzero
#include &sys/types.h&
#include &sys/stat.h&
#include &fcntl.h&
#include &unistd.h&
#define HELLO_WORLD_SERVER_PORT
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
int server_socket = socket(PF_INET,SOCK_STREAM,0);
if( server_socket & 0)
printf("Create Socket Failed!");
int opt =1;
setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//把socket和socket地址结构联系起来
if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
//server_socket用于监听
if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
printf("Server Listen Failed!");
while (1) //服务器端要一直运行
//定义客户端的socket地址结构client_addr
struct sockaddr_in client_
socklen_t length = sizeof(client_addr);
//接受一个到server_socket代表的socket的一个连接
//如果没有连接请求,就等待到有连接请求--这是accept函数的特性
//accept函数返回一个新的socket,这个socket(new_server_socket)用于同连接到的客户的通信
//new_server_socket代表了服务器和客户端之间的一个通信通道
//accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
if ( new_server_socket & 0)
printf("Server Accept Failed!\n");
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
if (length & 0)
printf("Server Recieve Data Failed!\n");
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
strncpy(file_name, buffer, strlen(buffer)&FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
int fp = open(file_name, O_RDONLY);
if( fp & 0 )
printf("%s\n",file_name);
FILE * fp = fopen(file_name,"r");
if(NULL == fp )
printf("File:\t%s Not Found\n", file_name);
bzero(buffer, BUFFER_SIZE);
int file_block_length = 0;
while( (file_block_length = read(fp,buffer,BUFFER_SIZE))&0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))&0)
printf("file_block_length = %d\n",file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0)&0)
printf("Send File:\t%s Failed\n", file_name);
bzero(buffer, BUFFER_SIZE);
close(fp);
fclose(fp);
printf("File:\t%s Transfer Finished\n",file_name);
//关闭与客户端的连接
close(new_server_socket);
//关闭监听用的socket
close(server_socket);
2.&[代码]c代码 client部分&&&&
#include &netinet/in.h&
// for sockaddr_in
#include &sys/types.h&
// for socket
#include &sys/socket.h&
// for socket
#include &stdio.h&
// for printf
#include &stdlib.h&
// for exit
#include &string.h&
// for bzero
#include &sys/types.h&
#include &sys/stat.h&
#include &fcntl.h&
#include &unistd.h&
#define HELLO_WORLD_SERVER_PORT
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
if (argc != 2)
printf("Usage: ./%s ServerIPAddress\n",argv[0]);
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET;
//internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0);
//0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_STREAM,0);
if( client_socket & 0)
printf("Create Socket Failed!\n");
//把客户机的socket和客户机的socket地址结构联系起来
if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
printf("Client Bind Port Failed!\n");
//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
struct sockaddr_in server_
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
printf("Server IP Address Error!\n");
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
//向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) & 0)
printf("Can Not Connect To %s!\n",argv[1]);
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
printf("Please Input File Name On Server:\t");
scanf("%s", file_name);
char buffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);
strncpy(buffer, file_name, strlen(file_name)&BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
send(client_socket,buffer,BUFFER_SIZE,0);
int fp = open(file_name, O_WRONLY|O_CREAT);
if( fp & 0 )
FILE * fp = fopen(file_name,"w");
if(NULL == fp )
printf("File:\t%s Can Not Open To Write\n", file_name);
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
int length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
if(length & 0)
printf("Recieve Data From Server %s Failed!\n", argv[1]);
int write_length = write(fp, buffer,length);
int write_length = fwrite(buffer,sizeof(char),length,fp);
if (write_length&length)
printf("File:\t%s Write Failed\n", file_name);
bzero(buffer,BUFFER_SIZE);
printf("Recieve File:\t %s From Server[%s] Finished\n",file_name, argv[1]);
close(fp);
//关闭socket
close(client_socket);
3.&[代码]open等,fopen等说明&&&&
某些注释部分,open,read,write被 fopen,fread,fwrite替换。
说明一下:
fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等
缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,
从磁盘文件将数据先读入内存“缓冲区”, 装满后再从内存“缓冲区”依此读入接收的变量。执行写文件的
操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存
“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,
执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。
open, close, read, write, getc, getchar, putc, putchar 等
非缓冲文件系统
非缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、
字符串、格式化数据,也可以读写二进制数 据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对
文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,
由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。
open等属于低级IO,
fopen等是高级IO。
open等返回一个文件描述符(用户程序区的),
fopen等返回一个文件指针。
open等无缓冲,fopen等有缓冲。
fopen等是在open等的基础上扩充而来的,在大多数情况下,用fopen等。
open 是系统调用 返回的是文件句柄,文件的句柄是文件在文件描述符表里的索引,
fopen是C的库函数,返回的是一个指向文件结构的指针。
开源中国-程序员在线工具:
2楼:un163tom 发表于
client输入一个文件名-&发送要下载的文件名-&server接收文件名-&server打开相应的文件-&server读取该文件,将文件内容存储到buffer-&server发送buffer-&client接收buffer数据,并将bufferr写入到文件句柄为fp的文件中-&client结束,但server一直运行,等待client的再次连接
3楼:xcch 发表于
4楼:gdcc 发表于
fclose (fp)好吧!
5楼:吴跃明 发表于
不错,学习了
6楼:戚继光 发表于
楼主这个可以并行发送消息吗?就是多个客户端同时访问?
7楼:txh2002 发表于
这个是用的什么开发工具?
8楼:txh2002 发表于
是linux下运行的工具吗?
9楼:mickelfeng 发表于
想问下,假如server端用的是tcp创建的socket,客户端用udp能链接吗
10楼:Jarek 发表于
引用来自“mickelfeng”的评论想问下,假如server端用的是tcp创建的socket,客户端用udp能链接吗
不可以的,二者的协议不同。
11楼:_小卒过河_ 发表于
问问多多!楼主你自己测试了吗?
12楼:郑少雄 发表于
我试过了,确实可以用的!!
13楼:令人发狂的菜鸟 发表于
引用来自“郑少雄”的评论我试过了,确实可以用的!!我想通过这个demo实现板子和我的上位机的通信。情况是这样的:我把server.c gcc了一把,在上位机上运行,生成了a.out文件。然后./a.out试了一下 说要输入ipaddr,然后我加上了本机的ip,提示不能连接。 是不是这个例程还得修改才能用呢?
14楼:IT屌丝 发表于
上面的程序有问题的,服务器与客户端是可以通信,但是你发个有内容的文件过去看看,会把文件内容清空。
15楼:ibmo 发表于
发现client.c 有几处错误:
(1) 75 行 send 函数的第三个参数的错误的
(2)107 行的fp 应该使用fclose 关
(3)有些函数没给定头文件,编译器警告
16楼:且行且飘逸 发表于
server端占用内存大概700多K,有没有办法精简一些?嵌入式资源紧张!!有懂的大神?
17楼:Xiqincai 发表于
&我喜欢代码简洁易读,服务稳定的推送服务,前段时间研究了一下goeasy,后台推送只需要两行代码,&js前端推送也只需要3,4行,而且文档齐全,还提供了后台查询信息收发情况,所以我觉得GoEasy推送服务是个不错的选择。
快速入门:goeasy.io/www/started.jsp
GoEasy web实时推送官网:https://goeasy.io
1. 引入goeasy.js
2. 客户端订阅,
&& Var goeasy = new
GoEasy({appkey:’your appkey’});
goeasy.subscribe(channel:”your
channel”, onMessage:function(message){alert(‘received message’+ message.content)})
3. 三种推送方式
&& Javascript:
goeasy.publish({channel:’your channel’, message:’your publish msg’});
&& Java SDK: GoEasy
goeasy = new GoEasy(“appkey”); goeasy.publish(“your channel”,”your msg”);
&& RestAPI:
三步轻松实现web推送及接收。
开源从代码分享开始
marsing的其它代码

我要回帖

更多关于 服务器端产品生产上报单条产品信息 的文章

 

随机推荐