一, socket 函数
1, 头文件:
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
2, 函数原型:
int socket(int domain, int type, int protocol);
socket 函数类似于 open, 用来打开一个网络连接, 如果成功则返回一个网络文件描述符(int 类型), 之后我们操作这个网络连接都通过这个网络文件描述符.
dimain: 域, 网络域, 网络地址范围(IPV4 或 IPV6 等), 也就是协议簇
type: 指定套接字类型: SOCK_STREAM(TCP 网络),SOCK_DGRAM(UDP),SOCK_SEQPACKET
protocol: 指定协议, 如果指定 0, 表示使用默认的协议
3, 函数形参:
- 3.1,domain:(域)
- AF_INET ipAF_INET6 ipv6
AF_PACKET packet 低级数据包接口
PF_PACKET 不懂, 待了解
PF_INET 待了解(AF 开头的表示地址族, PF 开头的表示协议族, 协议族包含多个地址族, 但是当前这种还从未实现, 而在 < sys/socket.h > 中 PF 的值总是与 AF 的值相等的)
3.2,type:(套接字类型):
SOCK_RAW 原始套接字 -->使用原始套接字时候调用, 原始套接字也就是链路层协议
SOCK_STREAM 字节流套接字 -->提供顺序, 可靠, 双向, 基于连接的字节流. 可以支持带外数据传输机制. 例如: TCP 协议, FTP 协议
SOCK_DGRAM 数据报套接字 -->支持数据报 (无连接, 不可靠的固定最大长度的消息) 例如: UDP 协议
SOCK_SEQPACKET 有序分组套接字 -->为固定最大长度的数据报提供有序, 可靠, 双向连接的数据传输路径; 消费者需要利用每个输入系统调用读取整个分组
3.3,protocol(协议):
IPPROTO_IP IP 传输协议
IPPROTO_TCP TCP 传输协议
IPPROTO_UDP UDP 协议
IPPROTO_SCTP SCTP 传输协议
IPPROTO_ICMP ICMP 协议
IPPROTO_IGMP IGMP 协议
一般情况下 IPPROTO_TCP,IPPROTO_UDP,IPPROTO_ICMP 协议用的最多, UDP 协议 protocol 就取 IPPROTO_UDP,TCP 协议 protocol 就取 IPPROTO_TCP; 一般情况下, 我们让 protocol 等于 0 就可以, 系统会给它默认的协议. 但是要是使用 raw socket 协议, protocol 就不能简单设为 0, 要与 type 参数匹配.
4, 返回值:
成功时返回一个小的非负整数值, 他与文件描述符类似, 我们称为套接字描述符, 简称 sockfd. 失败, 则返回 - 1.
5, 例子:
- /*--------------------- 创建一个监听 socket-------------------*/
- if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- perror("socket() error\n");
- exit(1);
- }
二, bind 函数
1, 头文件:
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
2, 函数原型:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
服务端套接字绑定自己的 IP 地址与端口号, 客户端那边可以不写, 内核会给它分配一个临时的端口.
3, 函数形参:
3.1,sockfd: 服务器或者客户端自己创建的 socket
3.2,addr: 服务器或者客户端自己的地址信息(协议族, IP, 端口号)
3.3,addrlen: 服务器或者客户端自己的地址信息的长度
4, 返回值:
绑定成功, 返回 0, 失败返回 - 1
5, 例子:
- /*--------------------- 绑定 IP 和端口 bind----------------------*/
- bzero(&server, sizeof(server));
- server.sin_family = AF_INET;
- server.sin_port = htons(port);
- server.sin_addr.s_addr = inet_addr(ip);
- if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
- {
- perror("bind() error\n");
- exit(1);
- }
三, connect 函数
1, 头文件:
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
2, 函数原型:
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
TCP 客户端通过 connect 函数与服务端连接, 进行通信.
3, 函数形参:
- 3.1,sockfd(客户端自己创建的 sock)
- 3.2,addr(服务端地址族, 服务端 IP 地址, 服务端端口号)
- 3.3,addrlen(服务端地址字节长度)
4, 返回值:
连接成功, 返回 0, 连接失败, 返回 - 1
5, 例子:
- struct sockaddr_in client;
- addrlen = sizeof(client);
- if ((connetfd = accept(listenfd, (struct sockaddr *)&client, &addrlen)) == -1)
- {
- perror("accept() error\n");
- exit(1);
- }
接下来给出一个大例子, tcp--socket 套接字通信, 结合 sqlite3 数据库操作
- #include<stdio.h>
- #include<stdlib.h>
- #include<netinet/in.h>
- #include<sys/socket.h>
- #include<sys/types.h>
- #include<unistd.h>
- #include<string.h>
- intmain()
- {
- structsockaddr_in server;
- structsockaddr_in client;
- intlistenfd, connetfd;
- charip[20];
- intport;
- intaddrlen;
- charrebuf[100];
- charwrbuf[100];
- chartmp[100];
- intrevlen;
- /*--------------------- 创建一个监听 socket-------------------*/
- if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- perror("socket() error\n");
- exit(1);
- }
- /*---------------------- 输入要监听的 IP 和端口 ----------------------*/
- printf("Please input the ip:\n");
- scanf("%s", ip);
- printf("Please input the port:\n");
- scanf("%d", &port);
- /*--------------------- 绑定 IP 和端口 bind----------------------*/
- bzero(&server, sizeof(server));
- server.sin_family= AF_INET;
- server.sin_port= htons(port);
- server.sin_addr.s_addr= inet_addr(ip);
- if(bind(listenfd, (structsockaddr *)&server, sizeof(server)) == -1)
- {
- perror("bind() error\n");
- exit(1);
- }
- /*---------------------- 开始监听 listen-------------------*/
- if(listen(listenfd, 20) == -1)
- {
- perror("listen() error\n");
- exit(1);
- }
- intclient_pid = 0;
- while(1)
- {
- /*----------------------accept------------------*/
- addrlen = sizeof(client);
- if((connetfd = accept(listenfd, (structsockaddr *)&client, &addrlen)) == -1)
- {
- perror("accept() error\n");
- exit(1);
- }
- /*---------------------show client---------------*/
- printf("connect successful!\n");
- printf("the client ip is %s,port is %d\n", inet_ntoa(client.sin_addr), ntohs(port));
- client_pid = fork();
- if(client_pid == 0)
- {
- // 子进程
- close(listenfd); // 关闭监听请求
- /*----------------------read and write----------*/
- intserial = 0;
- while(1)
- {
- bzero(rebuf, sizeof(rebuf));
- revlen = read(connetfd, rebuf, sizeof(rebuf));
- if((memcmp("bye", rebuf, 3)) == 0)
- {
- printf("Bye-bye then close the connect...\n");
- break;
- }
- bzero(wrbuf, sizeof(wrbuf));
- bzero(tmp, sizeof(tmp));
- sprintf(tmp, "%d", serial);
- strcat(tmp, rebuf);
- bcopy(tmp, wrbuf, strlen(tmp));
- write(connetfd, wrbuf, sizeof(wrbuf));
- rebuf[revlen] = '\0';
- printf("the info from client is:%s\n", rebuf);
- serial++;
- }
- return0;
- }
- close(connetfd); // 父进程关闭连接请求
- }
- return0;
- }
来源: https://www.cnblogs.com/GotWindy/p/11066976.html