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 ...
随机推荐
- json,pickle模块
序列化 把对象从内存中编成可储存或传输的过程称之为序列化,输出为json串,.json文件 反序列化 把json串反编成Python数据类型 json模块 用于跨平台交互 json模块下不可转换集合( ...
- sqlite数据库文件导入到sqlserver 2016-03-26 21:55 1292人阅读 评论(1) 收藏
最近在公司做项目,需要做两个版本,都是cs的,然后要求是一个单机版,自带数据库,另一个要进行局域网内的连接,所以公司的大牛设计是,局域网版的用sqlserver2008,单机版的则用sqlite.然后 ...
- Mysterious Antiques in Sackler Museum(判断长方形)
题目链接 参考博客Ritchie丶的博客 - UVALive 7267 Mysterious Antiques in Sackler Museum (判断长方形) 题意:大概意思就是判断四个矩形能不能 ...
- 阿里开源新一代 AI 算法模型,由达摩院90后科学家研发
最炫的技术新知.最热门的大咖公开课.最有趣的开发者活动.最实用的工具干货,就在<开发者必读>! 每日集成开发者社区精品内容,你身边的技术资讯管家. 每日头条 阿里开源新一代 AI 算法模型 ...
- linux cat /etc/passwd 说明
通常在Linux系统中,用户的关键信息被存放在系统的/etc/passwd文件中,系统的每一个合法用户账号对应于该文件中的一行记录.这行记录定义了每个用户账号的属性.下面是一个passwd文件的示例( ...
- 2018-2-13-WPF-只允许打开一个实例
title author date CreateTime categories WPF 只允许打开一个实例 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17:2 ...
- Redis源码解析:03字典
字典是一种用于保存键值对(key value pair)的抽象数据结构.在字典中,一个键和一个值进行关联,就是所谓的键值对.字典中的每个键都是独一无二的,可以根据键查找.更新值,或者删除整个键值对等等 ...
- Xib设计UITableViewCell然后动态加载
转自: http://www.2cto.com/kf/201202/120764.html (注:环境Mac OS X Lion 10.7.3 + Xcode 4.2.1 + iOS SDK 5.0. ...
- iptables 规则(Rules)
iptables的每一条规则(rule),都是由两部分组成的,第一部分包含一或多个「过滤条件」其作用是检查包是否符合处理条件(所有条件都必须成立才算数) :第而部分称为「目标」,用於決定如何处置符合条 ...
- python项目管理
Python 通常没有对应 Java 的 Ant / Maven 这样的 build tool,有一个用于打包的 setuptools / distutils 但也并不完全等价.如果是用来管理依赖包, ...