首页 > 代码库 > TCP之简单回传(三)
TCP之简单回传(三)
鉴于TCP之简单回传(一) 中所出现的问题,本博文所要采取的一种方法是:
服务器端和客户端共同遵守如下约定:接收的字节流中,若遇到‘\n‘,表示一次传送完毕。
具体为:
客户端把每次欲发送的数据的最后一个字符设置为 ‘\n‘;
而服务器每次接收时,一个一个字符的从缓冲区中取出一个字符,然后再判断该字符是否为‘\n‘,若不是,则继续读取;若是,则退出循环,表示本次接收结束;
实现代码如下:
//按字符读取--->由于每读取一个字符就产生一次系统调用,故效率较低ssize_t readline_slow(int fd, void *usrbuf, size_t maxlen){ char *bufp = (char*)usrbuf;//偏移位置 ssize_t nread; size_t nleft = maxlen -1 ;//剩余字节数 char ch;//保存每次读取的字符 while( nleft > 0)//只要还有没读的,就一直循环 { if(-1 == (nread=read(fd, &ch, 1)))//把从fd中读取的字符存进ch中 { if(errno == EINTR)//被中断信号打断 continue; return -1;//err }else if(0 == nread ) break; //EOF *bufp = ch;//将读取的字符存进buf bufp++;//向前移动 nleft --;//剩余字节数-- if(ch == ‘\n‘)//如果该字符为\n。本次读取完成 break; } *bufp =‘\0‘;// return (maxlen- nleft -1);//最大长度 -剩余的字符 - ‘\0‘}
本程序中所用到的函数都可以在 TCP之函数封装 中找到;
server服务器端:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)void do_server(int fd);int main(int argc, const char *argv[]){//socket int listenfd = socket(AF_INET, SOCK_STREAM, 0 ); if( -1 == listenfd) ERR_EXIT("socket");//地址复用 int on = 1; if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0) ERR_EXIT("setsockopt");//bind struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(8888); //主机字节序转化为网络字节序 addr.sin_addr.s_addr = inet_addr("127.0.0.1");//点分十进制转化成网络字节序 if( -1 == bind( listenfd, (struct sockaddr*)&addr, sizeof(addr))) ERR_EXIT("bind");//listen if( -1 == listen(listenfd,SOMAXCONN )) ERR_EXIT("listen"); //accept int peerfd = accept(listenfd, NULL, NULL);//对方的IP&PORT//read&write do_server(peerfd);//close close(peerfd); close(listenfd); return 0;}void do_server(int fd){ char recvbuf[1024100] = {0}; int cnt =0; while(1) { int nread = readline_slow(fd, recvbuf, sizeof(recvbuf)); if(nread == -1)//err { if(errno == EINTR) continue; ERR_EXIT("read"); }else if (nread == 0 )//write close { printf("close...\n"); exit(EXIT_FAILURE); } // ok printf("count = %d recv size = %d\n",++cnt, nread); memset(recvbuf, 0, sizeof(recvbuf)); }}
client客户端:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)void do_server(int fd);int main(int argc, const char *argv[]){//socket int peerfd = socket(AF_INET, SOCK_STREAM,0); if( -1 == peerfd) ERR_EXIT("socket");//connect struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8888); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if( -1 == connect(peerfd,(struct sockaddr*)&addr, sizeof(addr) )) ERR_EXIT("connect");//read&write do_server(peerfd); return 0;}void do_server(int fd){ #define SIZE 1024 char sendbuf[SIZE +1]= {0}; int i ; for (i = 0; i < SIZE-1; i++) //attention { sendbuf[i]= ‘a‘; } sendbuf[SIZE-1] = ‘\n‘;//标志位 int cnt =0; while(1) { int i; for (i = 0; i < 10; i++) { int nwrite =writen(fd, sendbuf, SIZE);//发送SIZE个数据中最后一个字符为\n if( nwrite != SIZE) ERR_EXIT("writen"); printf("cout = %d,write %d bytes\n",++cnt, SIZE); } nano_sleep(4.5); }}
测试结果:
./servercount = 1 recv size = 1024count = 2 recv size = 1024count = 3 recv size = 1024count = 4 recv size = 1024count = 5 recv size = 1024count = 6 recv size = 1024count = 7 recv size = 1024count = 8 recv size = 1024count = 9 recv size = 1024count = 10 recv size = 1024count = 11 recv size = 1024count = 12 recv size = 1024count = 13 recv size = 1024count = 14 recv size = 1024count = 15 recv size = 1024count = 16 recv size = 1024count = 17 recv size = 1024count = 18 recv size = 1024count = 19 recv size = 1024count = 20 recv size = 1024
./clientcount = 1 recv size = 1024count = 2 recv size = 1024count = 3 recv size = 1024count = 4 recv size = 1024count = 5 recv size = 1024count = 6 recv size = 1024count = 7 recv size = 1024count = 8 recv size = 1024count = 9 recv size = 1024count = 10 recv size = 1024count = 11 recv size = 1024count = 12 recv size = 1024count = 13 recv size = 1024count = 14 recv size = 1024count = 15 recv size = 1024count = 16 recv size = 1024count = 17 recv size = 1024count = 18 recv size = 1024count = 19 recv size = 1024count = 20 recv size = 1024
注意:本程序效率比较低下,原因在于:
每次读取一个字符都要系统调用一次read函数。
解决方法:TCP之简单回传(四)
TCP之简单回传(三)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。