唯有前进值得敬仰

---等得越久,相聚时越幸福
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

linux socket编程基础2

Posted on 2010-07-09 15:40  绿豆芽33  阅读(533)  评论(1编辑  收藏  举报

一、基本套接字函数

socket,connect,bind,listen,accept,close

函数socket创建的套接字是主动套接字,可以用来进行主动连接(调用connect),但是不能接收连接请求,

而服务器的套接字必须能够接受客户机的请求,函数listen的作用就是将一个尚未连接的主动套接字转换成一

个被动套接字(称之为倾听套接字):告诉TCP协议,可以接受连接请求。

 

倾听套接字是专门用来接收客户机连接请求,完成3次握手操作而用的,TCP不能使用它来标识TCP连接,这样就

需要创建一个新的套接字来标识这个要接收的连接,并将他的描述符返回给应用程序,此即accept的作用。

说明:一个服务器进程通常只需要创建一个倾听套接字,在服务器进程的整个活动期间,用它来接收所有客户机的

连接请求,在服务器进程终止前close这个倾听套接字,而对于每个accept的连接,TCP都创建一个新的连接套接字

来标识这个连接,当服务器处理完这个客户机的请求时,就可以close这个套接字。

 

二、读写数据函数

read,write,send,receive,sendto,recvfrom(以后介绍)

与读写文件操作类似

read操作时:3种返回结果:>0,=0,<0;分别对应正常返回,读到文件结束符和读错误。

write操作时,2种返回结果:>0,<0;分别表示正常与错误。

可以编写两个读写函数包含错误处理,以方便使用,如

#include<errno.h>
#include<unistd.h>
int read_all(int fd,void*buf,int n)
{
  int nleft;
  int nbytes;
  char *ptr;
  ptr=buf;
  nleft=n;
  for(;nleft>0;){
    nbytes=read(fd,ptr,nleft);
    if(nbytes<0){
      if(errno==EINTR)nbytes=0;
      else return -1;
    }
    else if(nbytes==0)break;
    nleft-=nbytes;
    ptr+=nbytes;
  }
  return n-nleft;
}
int write_all(int fd,void*buf,int n)
{
  int nleft;
  int nbytes;
  char *ptr;
  ptr=buf;
  nleft=n;
  for(;nleft>0;){
    nbytes=write(fd,ptr,nleft);
    if(nbytes<=0){
      if(errno==EINTR)nbytes=0;
      else return -1;
    }
    
    nleft-=nbytes;
    ptr+=nbytes;
  }
  return n;
}

三、其他函数
getsockname和getpeername
分别返回套接字的本地地址和对应的远程地址。
1.域名查找函数
gethostbyname,gethostbyaddr,uname,gethostname
struct hostent* gethostbyname(const char*hostname);
查询指定的域名地址所对应的IP地址,成功返回一个hostent指针结构,否则返回NULL。
struct hostent{
char *h_name;//主机正式名称
char **h_aliases;//别名列表
int h_addrtype;//地址类型,AF_INET for ipv4
int h_length;//地址长度,32bit for ipv4
char **h_addr_list;//主机的ip地址列表
};
#define h_addr h_addr_list[0];

2.查询指定的IP地址对应的域名 
#include<netdb.h>
struct hostent *gethostbyaddr(const char *addr,size_t len,int family)

参数addr实际上是一个指向in_addr结构类型的指针,包含要查询的ip地址,len指示其长度family=AF_INET。返回的结果位于hostent结构的h_name域。
【在网络程序中为了便于使用,应能处理ip地址和域名地址两种地址形式,对于一个给定的地址,一般先假设是个ip地址,用inet_aton处理,如果失败,在进行域名查找。比如下面的通用地址处理函数】
int addr_generic(char*address,struct in_addr *inaddr){
  struct hostent *he;
  if(inet_aton(address,inaddr)==1)return 1;
  he=gethostbyname(address);
  if(he!=NULL){
    *inaddr=*(struct in_addr*)he->he_addr->list[0];
    return 1;  }
  else return 0;
}

3.uname与gethostname返回本机器的域名地址

一般用uname获取本机的名称,作为gethostname的参数获取本机ip。
如uname(&myname);//struct utsname myname;
he=gethostname(myname.nodename)

  
  4.服务有关的函数
  getservbyname,getservbyport

  struct servent*getservbyname(const char*servname,const char*protostrname);//查找服务的端口号

  struct servent *getservbyport(int port,const char *protoname)//查找端口的服务
  端口均是网络字节顺序的。

struct servent{

char *s_name;

char **s_aliases;

int s_port;

char *s_proto;

};

四、网络数据格式

文本字符串,二进制数据无需进行特殊的处理,整数的发送和接收需要进行一些处理。

16位,32位可以借助htons&ntohs和htonl&ntohl转换,64位的则需要借助函数vsprintf和sscanf

比如:void sender(int sockfd,long data)

{ char buf[10];

  sprintf(buf,"%ld",data);

  write(sockfd,buf,strlen(buf));

}

void receiver(int sockfd,long *data)

{

  char buf[10];

  read(sockfd,buf,sizeof(buf));

  sscanf(buf,"ld",data);

}

指针数据的传输:只能传输指针所指的具体内容;

结构体数据的传输:发送方依次传送结构体中各成员变量,而接收方使用相同的顺序接收个成员变量。

浮点数据的传输:可以字符串形式发送和接收。

 

本文参考《linux网络编程》