Unix网络编程(一)基本字段和常用函数
1.基本字段
2.常用函数
基本字段
用来表示地址的结构有两个,都是定义在in.h中,分别是sockaddr_in和sockaddr。通常定义并初始化sockaddr_in,在使用函数传递参数时将其强转为后者,因为在大多数函数中,要求的指针类型都sockaddr,然而sockaddr_in的字段较为丰富,容易赋值。
具体的字段定义如下
sockaddr_in
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
sockaddr
/* Structure describing a generic socket address. */
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
在这里特别要提的是
第一个字段__SOCKADDR_COMMON 在sockaddr.h中定义为
#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family
就是以前的sa_family_t类型的名为sin_family的字段。代表着该socket使用的协议族。常用的有AF_INET和AF_INET6,前者代表Ipv4,后者代表Ipv6。
以及sockaddr_in的最后一个字段sin_zero,它是通过计算,让sockaddr_in和sockaddr保持同样的空间大小,保证转换时的完整性。
基本函数
socket()
int socket(int domain, int type, int protocol);
作用:建立一个新的socket
返回值:成功则返回socket对应的代码,失败则为-1
参数:
1.第一个参数指定何种类型的协议族,常用有AF_INET和AF_INET6两种。完整的定义在/usr/include/bits/socket.h 内
2.第二个参数指定类型,常用的是SOCK_STREAM(TCP协议),SOCK_DGRAM(UDP协议)。
3.第三的参数指定传输协议,但因为会自动设置为type参数所对应的协议。因此设置为0即可
connect()
int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
作用:将socket 连至参数serv_addr 指定的网络地址
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中.
参数:
1.第一个是socket
2.第二个是sockaddr的指针
3.第三个是指针的长度(大小)
bind()
int bind (int sockfd, struct sockaddr * my_addr, int addrlen)
作用:用于将本地地址与socket捆绑
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中.
参数:
1.第一个是socket
2.第二个是sockaddr的指针
3.第三个是指针的长度(大小)
listen()
int listen (int __fd, int __n)
作用:监听申请的连接
返回值:正确则返回0。否则的话,返回SOCKET_ERROR错误
参数:
1.第一个为socket的描述符
2.第二个为等待连接队列的最大长度。
accept()
int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
作用:接受来自指定socket的请求,并为该请求分配一个新的描述符
返回值:成功则返回新的socket 处理代码, 失败返回-1, 错误原因存于errno 中.
参数:
1. 第一个参数socket的描述符
2.第二个是sockaddr的指针
3.第三个是指针的长度(大小)
close()
int close (int __fd)
作用:释放对应的文件描述词
返回值:若文件顺利关闭则返回0, 发生错误时返回-1.
参数:
代码
以下是两个例子,
第一个是向13端口请求数据。(13端口是daytime服务的端口,返回所在主机的时间。因此运行时要求开启13端口)。
第二个是模拟daytime服务器,对访问13端口的请求返回主机时间。
请求13端口
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h>
int main()
{
int sockfd, n;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
char *IPaddress = "127.0.0.1";
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) /*创建socket*/
printf("socket error");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* 13端口是daytime服务 */
if (inet_pton(AF_INET, IPaddress, &servaddr.sin_addr) <= 0) /*该函数将字符型表达(presentation)转换位数值(number)*/
printf("inet_pton error for %s", argv[1]);
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)/*建立连接*/
printf("connect error");
while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { /*读取流信息*/
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF)
printf("fputs error");
}
if (n < 0)
printf("read error");
exit(0);
}
模拟daytime服务
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h>
#include <time.h>
int
main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len;
struct sockaddr_in servaddr, cliaddr;
char buff[MAXLINE];
time_t ticks;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);/*创建socket*/
bzero(&servaddr, sizeof(servaddr)); /*初始化servaddr,将其清空为0.可用memset函数代替,以下三步为其字段赋值*/
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*INADDR_ANY为0x00000000 ,意为接收任何来到该地址的请求*/
servaddr.sin_port = htons(13);
bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); /*将socket与本机指定端口和地址捆绑*/
listen(listenfd, LISTENQ); /*开启监听*/
for ( ; ; ) {
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA *) &cliaddr, &len); /*当有连接时,将该连接的句柄绑定到connfd上*/
printf("connection from %s, port %d\n", /*打印请求地址*/
Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
ntohs(cliaddr.sin_port));
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); /*返回时间*/
write(connfd, buff, strlen(buff));
close(connfd);
}
}