主要内容
read,write 与 recv,send之间的区别
readline的实现
用readline实现回射客户/服务器
getsockname,getpeername
gethostname,gethostbyname,gethostbyaddr 相关的系统调用
第一点:read,write 与 recv,send之间的区别
1.recv,send 只能用于sock编程,read write可用于其他
2. ssize_t recv(int sockfd, void *buf, size_t len, int flags); 最后一个参数可以指定
这个函数的行为。flags 指定为MSG_PEEK表明当读取缓冲区的数据时候,并不会清空缓存区中的数据,而read会清空缓冲区中的数据
第二点:readline的函数的实现
ssize_t recv_peek(int sockfd,void *buf,size_t len)
{
while (1)
{
int ret = recv(sockfd,buf,len,MSG_PEEK); //并没有清空缓存区中的内容
if (ret==-1 && errno == EINTR) //信号发生了中断
continue;
return ret;
}
}
/*
两种可能:
第一种可能:当读取的长度大于maxline,则跳出
第二种可能:当读取的长度中有/n选项,则跳出
*/
ssize_t readline(int sockfd,void *buf,size_t maxline)
{
int ret;
int nread;
char * bufp = buf;
int nleft = maxline;
while(1)
{
ret = recv_peek(sockfd,bufp,nleft);
if(ret < 0)
{
return ret;
}
else if (ret == 0)
{
return ret;
}
nread = ret; //读取到的数据 进而判断读取到的数据中是否含有\n选项
int i;
for (i=0;i<nread;i++)
{
if(bufp[i] == '\n')
{
ret = readn(sockfd,bufp,i+1); //把数据清空了
if(ret!=i+1)
exit(EXIT_FAILURE);
return ret;
}
}
//说明不满足/n ,也需要把数据读取出来放到缓存区中
if(nread > nleft)
{
exit(EXIT_FAILURE);
}
nleft -= nread;
ret = readn(sockfd,bufp,nread); //从套接口缓冲区移除
if(ret != nread)
{
exit(EXIT_FAILURE);
}
buf +=nread; //下一步进行下一步的偷窥
}
}
第三点:
getsockname,getpeername
gethostname,gethostbyname,gethostbyaddr 相关的系统调用
查看相关man手册,编写相关的测试代码
if(getsockname(sock, (struct sockaddr *)&localaddr, &addrlen) < 0)
{
ERR_EXIT("getsockname");
}
printf("ip = %s port = %d\n",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.sin_port));
char host[100] = {0};
if (gethostname(host,sizeof(host)) < 0)
{
ERR_EXIT("gethostname");
}
struct hostent *hp;
if ((hp = gethostbyname(host)) == NULL)
{
ERR_EXIT("gethostbyname");
}
//主机名字
printf("主机名 = %s\n",hp->h_name);
int i = 0;
while ((hp->h_addr_list)[i]!=NULL)
{
printf("%s\n",inet_ntoa(*(struct in_addr*)hp->h_addr_list[i]));
i++;
}