Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1412947
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: LINUX

2013-02-21 05:06:16

原文地址:socket编程相关函数使用 作者:Guobutter

字节序转换,字节序是指一个字节在存储器中是按高字节在前还是按低字节在前存放,分为大端格式和小端格式,异构计算机之间通信,需要转换自己的字节序为网络字节序。

字节序转换函数: (包含头文件:)

    uint32_t htonl() uint16_t htons()

    以上返回网络字节序

    uint32_t ntohl() uint16_t ntohs()

    以上返回主机字节序



以下函数包含头文件

通用套接口地址结构体

struct sockaddr
{
    sa_family_t sa_family;//地址族(无符号的短整数在linux中是两个字节)
    char sa_data[14];      //地址数据
}
在使用其他套接口地址时要强制转换成通用套接口地址 (struct sockaddr *)&servAddr 

IPv4套接字地址结构体

struct sockaddr_in

{

    sa_family_t sin_family; 协议类型

    in_port_t sin_port; 端口号

    struct in_addr sin_addr; IP地址

    unsigned char zero[8]; 0

};

Ip地址结构体:

struct in_addr

{

    in_addr_t s_addr;

};

    struct in_addr以一个32位无符号数来表示,通常需要用到点分十进制数串与它之间的转换,使用inet_ptoninet_ntop来处理网络字节和主机字节之间的转换,原型如下:

int inet_pton(int family, const char *strptr, void *addrptr);

如果使用IPv4协议,第一个参数是AF_INET

第二个参数strprt为指向字符型的地址(ddd.ddd.ddd.ddd格式),函数将该地址转换为in_addr的结构体,并复制在*addrptr中。成功返回1,否则返回0

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

这个函数作用和上面相反,多了一个参数len,它是所指向缓存区addrptr的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针。


有一个宏定义,指定了IP地址的长度为16,可以直接拿来用

#define INET_ADDRSTRLEN 16


以下函数包含头文件

三、建立Socket
  创建套接字是进行任何网络通信时必须做的第一步,创建一个用于网络通信的I/O描述符(套接字),相当于在对文件读写前先用open获取文件描述符

为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。Socket函数原型为:

int socket(int family, int type, int protocol);

family:协议族 常用的是AF_INET,代表的是IPv4协议,AF_INET6IPv6协议

type:套接口类型 SOCK_STREAM SOCK_DGRAM

protocol:协议类别,一般为0就可以了。

    调用socket函数返回一个int型的socket描述符。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。


四、做为服务器

做为服务器需要具备三个条件:

1.具备一个可以确知的地址,以便别人能找到我

2.让操作系统知道你是一个服务器,而不是一个客户端

3.等待连接的到来


1.使用一个确知的端口来接收客户端的连接,需要使用bind函数将一个地址绑定到套接字,bind函数原型如下:

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

sockfd:套接口描述字 myaddr:指向特定于协议的地址结构体指针

addrlen: 该地址结构的长度 返回值:0,成功;其他,失败


2.让套接字成为被动的,使用listen函数可以将套接口由主动修改为被动,listen函数原型如下:

int listen(int sockfd, int backlog);

sockfd: socket套接口描述字 backlog:连接队列的长度

返回值:0,成功;其他,失败


3.等待连接的到来,使用accept函数从连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待(这个函数是阻塞的)。函数原型如下:

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

sockfd: socket套接口描述字 cliaddr: 客户端地址

addrlen:客户端地址结构体长度 返回值:已连接的套接口(代表当前连接)


五、做为客户端

客户端要知道服务哭的IP地址以及端口号,需要主动跟服务器建立连接,对于TCP协议,连接建立后才可以开始传输数据,使用connect函数建立连接,原型如下:

int connect(int sockfd, const struct sockaddr *addr, socklen_t len);

addr: 服务器地址 addrlen:服务器地址结构体长度

返回值:0,成功;其他,错误。Connect函数建立连接后不会产生新的套接口


六、传输数据

    当连接建立后,通信的两端便具备两个套接口,可以用read,write函数从这个通信管道读取后写入数据.

         Send()和recv()这两个函数用于面向连接的socket上进行数据传输。
   Send()函数原型为:
   int  send(int  sockfd,   const void  *msg,   int  len,   int  flags);
Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。
   Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。
char *msg = "Hello!";
int len, bytes_sent;
……
len = strlen(msg);
bytes_sent = send(sockfd, msg,len,0);
……
   recv()函数原型为:
   int  recv(int  sockfd,  void  *buf, int  len,  unsigned int  flags);
   Sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。

    使用close函数关闭套接字,关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包。服务器关闭socket创建的套接字导致服务器无法继续接受新的连接,蛤不会影响已经建立的连接。关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器的监听。客户端用close,就是关闭连接。

 你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。
   int shutdown(int sockfd,  int how);
   Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:
   ·0-------不允许继续接收数据
   ·1-------不允许继续发送数据
   ·2-------不允许继续发送和接收数据,
   ·均为允许则调用close ()
   shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。

原文地址:http://qinjianbo2010.blog.163.com/blog/static/139893731201062010929953/

阅读(135) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~