read、write 与recv、send区别 gethostname
recv相对于read有什么区别呢?
其实它跟read函数功能一样,都可以从套接口缓冲区sockfd中取数据到buf,但是recv仅仅只能够用于套接口IO,并不能用于文件IO以及其它的IO,而read函数可以用于任何的IO;
recv函数相比read函数多了一个flags参数,通过这个参数可以指定接收的行为,比较有用的两个选项是:

这个这次要学习的,它可以接收缓冲区中的数据,但是并不从缓冲区中清除,这是跟read函数有区别的地方,read函数一旦读取了,就会直接从缓冲区中清除。
readline实现
也就是实现按行读取,读取直到\n字符,实际上,它也能解决上节中提到的粘包问题,回顾下上节的粘包问题解决方案:
包尾加\r\n(ftp)
我们只要解释\n为止,表示前面是一个条合法的消息,对于readline的实现,可以有三种方案:
①、最简单的方案就是一个字符一个字符的读取,然后做判断是否有"\n",但是这种效率比较低,因为会多次掉用read或recv系统函数。
②、用一个static变量保存接收到的数据进行缓存,在下次时从这个缓存变量中读取然后估"\n"判断。但是一旦用到了static变量,这意味着用到的函数是不可重录函数【关于这个概念,可以参考博文:http://www.cnblogs.com/webor2006/p/3744002.html】。
③、偷窥的方法,也就是这次要采用的方案。下面就利用我们封装的recv_peek函数实现readline:
server.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h> #define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(); ssize_t readn(int fd, void *buf, size_t count)//读取count个字节数,其中size_t是无符号
的整数,ssize_t是有符号的整数
{
size_t nleft = count;//剩余的字节数
printf("nleft = %d\n",nleft);
ssize_t nread;//已接收的字节数
char *bufp = (char*)buf; while (nleft > )
{//由于不能保证一次读操作能够返回字节数是多少,所以需要进行循环来接收
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)//被信号中断了,则继续执行,因为不是出错
continue;
return -;//表示读取失败了
}
else if (nread == )//对等方关闭了
return count - nleft;//返回已经读取的字节数 bufp += nread;
nleft -= nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == )//如果是这种情况,则表示什么都没发生,继续还得执行
continue; bufp += nwritten;
nleft -= nwritten;
} return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while()
{
int ret = recv(sockfd,buf,len,MSG_PEEK);
if(ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while()
{
ret = recv_peek(sockfd,bufp,nleft);
if(ret < )
return ret;
else if(ret == )
return ret;
nread = ret;
int i;
for(i = ; i<nread; i++)
{
if(bufp[i] == '\n')
{
ret = readn(sockfd,bufp,i+);
if(ret != i+)
exit(EXIT_FAILURE);
return ret;
}
} if(nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd,bufp,nread);
if(ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -;
} void do_service(int conn)
{
char recvbuf[];
//struct packet recvbuf;
int n;
while()
{
memset(recvbuf, , sizeof(recvbuf));
int ret=readline(conn,recvbuf,);
if(ret == -)
{
ERR_EXIT("readline");
}
if(ret == )
{
printf("client close\n");
break;
} fputs(recvbuf,stdout);
writen(conn,recvbuf,strlen(recvbuf));
}
} int main(void)
{
int listenfd;
if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < )
{
ERR_EXIT("socket");
}
struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
/*inet_aton("127.0.0.1",&servaddr.sin_addr);*/ //地址重用
int on=;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < )
{
ERR_EXIT("setsockopt");
} if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < )
{
ERR_EXIT("bind");
} if(listen(listenfd,SOMAXCONN) < )
{
ERR_EXIT("listen");
} struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int confd; pid_t pid;
while()
{
if((confd = accept(listenfd,(struct sockaddr*)&peeraddr, &peerlen)) < )
{
ERR_EXIT("accept");
}
printf("ip = %s, port = %d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
pid = fork();
if(pid == -)
{
ERR_EXIT("fork");
}
if(pid == )
{
close(listenfd);
do_service(confd);
exit(EXIT_SUCCESS);
}
else
{
close(confd);
}
} return ;
}
client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h> #define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(); ssize_t readn(int fd, void *buf, size_t count)//需要将函数的定义也挪过来
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == )
return count - nleft; bufp += nread;
nleft -= nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == )
continue;
bufp += nwritten;
nleft -= nwritten;
} return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while()
{
int ret = recv(sockfd,buf,len,MSG_PEEK);
if(ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while()
{
ret = recv_peek(sockfd,bufp,nleft);
if(ret < )
return ret;
else if(ret == )
return ret;
nread = ret;
int i;
for(i = ; i < nread; i++)
{
if(bufp[i] == '\n')
{
ret = readn(sockfd,bufp,i+);
if(ret != i+)
exit(EXIT_FAILURE);
return ret;
}
} if(nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd,bufp,nread);
if(ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -;
} int main(void)
{
int sockfd;
if((sockfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < )
{
ERR_EXIT("socket");
}
struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/*inet_aton("127.0.0.1",&servaddr.sin_addr);*/ if (connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < )
{
ERR_EXIT("connect");
} struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if(getsockname(sockfd,(struct sockaddr*)&localaddr,&addrlen) < )
ERR_EXIT("getsockname");
printf("ip = %s, port = %d\n",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.s
in_port)); char sendbuf[] = {};
char recvbuf[] = {};
//struct packet sendbuf;
//struct packet recvbuf;
//memset(&sendbuf,0,sizeof(sendbuf));
//memset(&recvbuf,0,sizeof(recvbuf)); int n; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
//writen(sockfd,sendbuf,sizeof(sendbuf));
//readn(sockfd,recvbuf,sizeof(recvbuf));
//n =strlen(sendbuf.buf);
//sendbuf.len = htonl(n);//网络字节序
writen(sockfd,sendbuf,strlen(sendbuf));
int ret = readline(sockfd,recvbuf,sizeof(recvbuf));
//int ret = readn(sockfd,&recvbuf.len,4);
if(ret == -)
{
ERR_EXIT("read");
}
else if(ret == )
{
printf("client close\n");
break;
} fputs(recvbuf,stdout);
memset(sendbuf,,sizeof(sendbuf));
memset(recvbuf,,sizeof(recvbuf));
}
close(sockfd);
return ;
}
Makefile
.PHONY: clean all
CC=gcc
CFLAGE= -G -Wall
BIN=client server getiplist
all:$(BIN)
%.o:%.c
$(CC) $(cflags) -C $< -O $@
clean:
rm -f *.o $(BIN)
getsockname:获取套接口本地的地址
当客户端成功与服务端连接之后,如果想知道客户端的地址,就可以通过它来获取,
getpeername:获取对等方的地址
由于它的使用方法跟getsockname一样,这里就不说明了,注意:sockfd需是连接成功的套接口,另外对于服务端获取客户端ip,像这种情况下也需用这个接口来获得:

gethostname:获取主机的名称
gethostbyname:通过主机名来获取主机上所有的ip地址
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int getlocalip(char *ip)
{
char host[] = {};
if (gethostname(host, sizeof(host)) < )
return -;
struct hostent *hp;
if ((hp = gethostbyname(host)) == NULL)
return -;
strcpy(ip, inet_ntoa(*(struct in_addr*)hp->h_addr_list[]));
return ; } int main(void)
{
char host[] = {};
if (gethostname(host, sizeof(host)) < )
ERR_EXIT("gethostname"); struct hostent *hp;
if ((hp = gethostbyname(host)) == NULL)
ERR_EXIT("gethostbyname"); int i = ;
while (hp->h_addr_list[i] != NULL)
{
printf("%s\n", inet_ntoa(*(struct in_addr*)hp->h_addr_list[i]));
i++;
} char ip[] = {};
getlocalip(ip);
printf("localip=%s\n", ip);
return ;
}
read、write 与recv、send区别 gethostname的更多相关文章
- C++socket编程write()、read()简介及与send()、recv()的区别
1. write 函数原型:ssize_t write(int fd, const void*buf,size_t nbytes)write函数将buf中的nbytes字节内容写入文件描述符fd.成功 ...
- recv send 阻塞和非阻塞
http://blog.csdn.net/xiaofei0859/article/details/6037814 int send( SOCKET s, const char FAR *buf, in ...
- 接口处理篇 accept bind connect atan2 htons inet_addr inet_aton inet_ntoa listen ntohl recv send sendto socket
accept(接受socket连线) 相关函数 socket,bind,listen,connect 表头文件 #include<sys/types.h> #include<sys/ ...
- Solidity transfer vs send 区别
原文地址: https://ethereum.stackexchange.com/questions/19341/address-send-vs-address-transfer-best-pract ...
- linux下recv 、send阻塞、非阻塞区别和用法
非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明: 基本概念: 阻塞IO:: socket 的阻塞模式 ...
- UNIX网络编程-recv、send、read、write之间的联系与区别
1.read ----------------------------------------------------------------------- #include <unistd.h ...
- 套接字I/O函数write/read writev/readv send/recv sendto/recvfrom sendmsg/recvmsg
函数原型 read/write系原型 #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); #include ...
- 一种构造WEB服务器端recv和send接口阻塞现象的方法
send阻塞 socket recv send接口阻塞,会导致服务器端不在响应客户端任何请求,所以一般情况, 会将socket设置为非阻塞状态, 但是有些场景,例如ssl_accept就需要使用阻塞的 ...
- linux内核中send与recv函数详解
Linux send与recv函数详解 1.简介 #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t n ...
随机推荐
- java.lang.StackOverflowError 解决办法
java.lang.StackOverflowError com.sxt.servlet.servlet1.LoginServlet.doGet(LoginServlet.java:15) com.s ...
- Gym - 101617D_Jumping Haybales(BFS)
Sample Input 4 2 .### #... .#.. #.#. 3 1 .#. .#. .#. Sample Output 4 -1 题意:给一个n*n的图,每次最多能跳k个格子,只能向南( ...
- Linux 用户he用户组管理
8)系统中有一类用户称为伪用户(psuedo users). 这些用户在/etc/passwd 文件中也占有一条记录,但是不能登陆,因为他们的登陆shell 为空,他们的存在主要是方便系统管理,满足 ...
- oracle函数 months_between(d1,d2)
[功能]:返回日期d1到日期d2之间的月数. [参数]:d1,d2 日期型 [返回]:数字 如果d1>d2,则返回正数 如果d1<d2,则返回负数 [示例] select sysdate, ...
- etcd 在超大规模数据场景下的性能优化
作者 | 阿里云智能事业部高级开发工程师 陈星宇(宇慕) 概述 etcd是一个开源的分布式的kv存储系统, 最近刚被cncf列为沙箱孵化项目.etcd的应用场景很广,很多地方都用到了它,例如kuber ...
- python中'0b111'中的b 是什么意思
https://zhidao.baidu.com/question/987330764742072579.html binary,二进制的意思
- min-width:100%和max-width:100%的区别
1.width:100%和width:auto width:100%,设定对象的宽度占父元素的100%不论设定元素的margin值是多少,不包含margin: width:auto,根据设定对象的实际 ...
- angular安装应用
首先你要有node 和npm 全局安装angular npm install -g @angular/cli 安装一个angular项目 ng new 项目名称 cd进入新建的项目 跑页 ...
- springboot2动态数据源的绑定
由于springboot2更新了绑定参数的api,部分springboot1用于绑定的工具类如RelaxedPropertyResolver已经无法在新版本中使用.本文实现参考了https://blo ...
- H3C 帧中继数据链路标识