UNIX C的一篇文章[2]

[入库:2005年8月19日] [更新:2007年3月24日]

本文简介:选择自 gimser 的 blog

构指针.
这两个函数失败时返回null 且设置h_errno错误变量,调用h_strerror()可以得到详细的
出错信息
3.3 字符串的ip和32位的ip转换.
在网络上面我们用的ip都是数字加点(192.168.0.1)构成的, 而在struct in_addr结构中
用的是32位的ip, 我们上面那个32位ip(c0a80001)是的192.168.0.1 为了转换我们可以
使用下面两个函数
int inet_aton(const char *cp,struct in_addr *inp)
char *inet_ntoa(struct in_addr in)
函数里面 a 代表 ascii n 代表network.第一个函数表示将a.b.c.d的ip转换为32位的i
p,存储在 inp指针里面.第二个是将32位ip转换为a.b.c.d的格式.
3.4 服务信息函数
在网络程序里面我们有时候需要知道端口.ip和服务信息.这个时候我们可以使用以下几
个函数
int getsockname(int sockfd,struct sockaddr *localaddr,int *addrlen)
int getpeername(int sockfd,struct sockaddr *peeraddr, int *addrlen)
struct servent *getservbyname(const char *servname,const char *protoname)
struct servent *getservbyport(int port,const char *protoname)
struct servent
{
char *s_name; /* 正式服务名 */
char **s_aliases; /* 别名列表 */
int s_port; /* 端口号 */
char *s_proto; /* 使用的协议 */
}
一般我们很少用这几个函数.对应客户端,当我们要得到连接的端口号时在connect调用成
功后使用可得到 系统分配的端口号.对于服务端,我们用inaddr_any填充后,为了得到连
接的ip我们可以在accept调用成功后 使用而得到ip地址.
在网络上有许多的默认端口和服务,比如端口21对ftp80对应www.为了得到指定的端口号
的服务 我们可以调用第四个函数,相反为了得到端口号可以调用第三个函数.
3.5 一个例子
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc ,char **argv)
{
struct sockaddr_in addr;
struct hostent *host;
char **alias;
if(argc<2)
{
fprintf(stderr,"usage:%s hostname|ip..\n\a",argv[0]);
exit(1);
}
argv++;
for(;*argv!=null;argv++)
{
/* 这里我们假设是ip*/
if(inet_aton(*argv,&addr.sin_addr)!=0)
{
host=gethostbyaddr((char *)&addr.sin_addr,4,af_inet);
printf("address information of ip %s\n",*argv);
}
else
{
/* 失败,难道是域名?*/
host=gethostbyname(*argv); printf("address information

of host %s\n",*argv);
}
if(host==null)
{
/* 都不是 ,算了不找了*/
fprintf(stderr,"no address information of %s\n",*arg
v);
continue;
}
printf("official host name %s\n",host->h_name);
printf("name aliases:");
for(alias=host->h_aliases;*alias!=null;alias++)
printf("%s ,",*alias);
printf("\nip address:");
for(alias=host->h_addr_list;*alias!=null;alias++)
printf("%s ,",inet_ntoa(*(struct in_addr *)(*alias)));
}
}
在这个例子里面,为了判断用户输入的是ip还是域名我们调用了两个函数,第一次我们假
设输入的是ip所以调用inet_aton, 失败的时候,再调用gethostbyname而得到信息.
--

网络编程(4)

4. 完整的读写函数
一旦我们建立了连接,我们的下一步就是进行通信了.在linux下面把我们前面建立的通道
看成是文件描述符,这样服务器端和客户端进行通信时候,只要往文件描述符里面读写东
西了. 就象我们往文件读写一样.
4.1 写函数write
ssize_t write(int fd,const void *buf,size_t nbytes)
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时
返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能
..
1)write的返回值大于0,表示写了部分或者是全部的数据.
2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理.
如果错误为eintr表示在写的时候出现了中断错误.
如果为epipe表示网络连接出现了问题(对方已经关闭了连接).
为了处理以上的情况,我们自己编写一个写函数来处理这几种情况.
int my_write(int fd,void *buffer,int length)
{
int bytes_left;
int written_bytes;
char *ptr;
ptr=buffer;
bytes_left=length;
while(bytes_left>0)
{
/* 开始写*/
written_bytes=write(fd,ptr,bytes_left);
if(written_bytes<=0) /* 出错了*/
{
if(errno==eintr) /* 中断错误 我们继续写*/
written_bytes=0;
else /* 其他错误 没有办法,只好撤退了*/
return(-1);
}
bytes_left-=written_bytes;
ptr+=written_bytes; /* 从剩下的地方继续写 */
}
return(0);
}
4.2 读函数read
ssize_t read(int fd,void *buf,size_t nbyte) read函数是负责从fd中读取内容.当读
成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于
0表示出现了错误.如果错误为eintr说明读是由中断引起的, 如果是econnrest表示网络
连接出了问题. 和上面一样,我们也写一个自己的读函数.
int my_read(int fd,void *buffer,int length)
{
int bytes_left;
int bytes_read;
char *ptr;
bytes_left=length;
while(bytes_left>0)
{
bytes_read=read(fd,ptr,bytes_read);
if(bytes_read<0)
{
if(errno==eintr)
bytes_read=0;
else
return(-1);
}
else if(bytes_read==0)
break;
bytes_left-=bytes_read;
ptr+=bytes_read;
}
return(length-bytes_left);
}
4.3 数据的传递
有了上面的两个函数,我们就可以向客户端或者是服务端传递数据了.比如我们要传递一
个结构.可以使用如下方式
/* 客户端向服务端写 */
struct my_struct my_struct_client;
write(fd,(void *)&my_struct_client,sizeof(struct my_struct);
/* 服务端的读*/
char buffer[sizeof(struct my_struct)];
struct *my_struct_server;
read(fd,(void *)buffer,sizeof(struct my_struct));
my_struct_server=(struct my_struct *)buffer;
在网络上传递数据时我们一般都是把数据转化为char类型的数据传递.接收的时候也是一
样的 注意的是我们没有必要在网络上传递指针(因为传递指针是没有任何意义的,我们必
须传递指针所指向的内容)
--

网络编程(5)

5. 用户数据报发送
我们前面已经学习网络程序的一个很大的部分,由这个部分的知识,我们实际上可以写出
大部分的基于tcp协议的网络程序了.现在在linux下的大部分程序都是用我们上面所

本文关键:UNIX C的一篇文章
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top