分类:
2012-07-18 15:00:30
原文地址: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_pton和inet_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_INET6是IPv6协议
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/