Fork me on GitHub

网络编程(三)


创建套接口

创建套接口的系统调用为socket,它的功能是生成一个套接口描述符

1
2
3
#include<sys/types.h>
#include<sys/socket.h>
int socket(int family,int type,int protocol);

返回:若成功则返回套接口描述符,若失败,则返回-1。

参数:family指明协议族,取值如PF_UNIXUNIX协议族),PF_INETIPv4协议族),PF_INET6IPv6协议),AF_ROUTE(路由套接口)等。type指明通信字节流类型,其取值如SOCK_STREAMTCP方式),SOCK_DGRAMUDP方式),SOCK_RAW(原始套接口),SOCK_PACKET(支持数据链路访问)等。一般来说,参数protocol可设置为0,除非用在原始套接口上(原始套接口有一些特殊的功能)

说明:在不严格区分的情况下,AF_INETPF_INET是可以混用的。PF代表Protocol Family(协议族),AF代表Address Family(地址族)

绑定套接口

socket函数创建一个套接口后,服务端需要使用bind()函数在这个套接口上绑定一个指定的端口号和IP地址。

1
2
3
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);

返回:若成功则返回0,若失败,则返回-1

参数:sockfd表示已经建立的socket编号(描述符),my_addr是一个指向sockaddr结构体类型的指针,参数addrlen表示my_addr结构的长度,可以用sizeof()函数来取得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

#define PORT 2345 // 定义端口号

int main(void)
{
int sockfd; // 定义套接口描述符
struct sockaddr_in addr; // 定义IPv4套接口地址数据结构addr
int addr_len = sizeof(struct sockaddr_in);
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) // 建立一个socket
{
perror("socket created error!");
exit(1);
}
else{
// socket创建成功
printf("socket created successfully!\n");
printf("socket id:%d\n",sockfd);
}
bzero(&addr,addr_len); //清空表示地址的结构体变量
// 设置addr的成员信息
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY); // IP地址设为本机IP
if(bind(sockfd,(struct sockaddr *)(&addr),sizeof(struct sockaddr)) < 0)
{
perror("bind error!");
exit(1);
}
else{
// 端口绑定成功
printf("bind port successfully!\n");
printf("local port:%d\n",PORT);
}
return 0;
}

等待监听函数

所谓监听,指的是服务端的socket的端口一直处于等待的状态,监听网络中的所有客户机,耐心等待某一客户机发送请求。如果客户端有连接请求,端口就会接受这个连接。listen()函数用于实现服务器的监听等待功能,它的函数原型如下。

1
2
#include<sys/types.h>
int listen(int sockfd,int backlog);

返回:若成功则返回0,若失败则返回-1。

参数sockfd用于表示已经建立的套接口,backlog表示能同时处理的最大连接请求数目,如果超过这个数目,客户端将会接收到ECONNREFUSED拒绝连接的错误。需要注意的是,listen并未真正的接受连接,只是设置socket的状态为监听模式,真正接受客户端连接的是accept函数。

listen函数只适用于SOCK_STREAMSOCK_SEQPACKETsocket类型。如果socketAF_INET,则参数backlog最大值可设置为128,即最多可以同时接受128个客户端的请求。

接受连接函数

服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。接受连接请求的函数是accept

1
2
3
#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socketlen_t *addrlen);

返回:若成功则返回新的套接口描述符,若失败,则返回-1。

参数:addr是一个sockaddr结构体类型的指针,系统会把远程主机的信息保存到这个指针所指向的结构体中,addrlen表示sockaddr的内存长度,可以用sizeof函数获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define PORT 2345

int main(void)
{
int sockfd,newsockfd; // 定义两个套接口描述符
struct sockaddr_in addr; // 定义IPv4套接口地址数据结构
int addr_len = sizeof(struct sockaddr_in);
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) // 建立一个socket
{
perror("socket created error!");
exit(1);
}
else{
// socket创建成功
printf("socket created successfully!\n");
printf("socket id:%d\n",sockfd);
}
bzero(&addr,addr_len);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 设IP地址为本机IP
if(bind(sockfd,(struct sockaddr *)(&addr),sizeof(struct sockaddr)) < 0)
{
perror("bind error!");
exit(1);
}
else{
printf("bind port successfully!");
printf("local port:%d\n",PORT);
}
if(listen(sockfd,5) < 0)
{
perror("listen error!");
exit(1);
}
else{
printf("Listening......\n");
}
if((newsockfd = accept(sockfd,(struct sockaddr *)(&addr),&addr_len)) < 0)
{
perror("accept error!");
exit(1);
}
else{
printf("accepted a new connection.\n"); // 已接受连接请求
printf("new socket id:%d\n",newsockfd);
}
return 0;
}
坚持原创技术分享,您的支持将鼓励我继续创作
-------------本文结束感谢您的阅读-------------
0%