一、域套接字相关概念
1> 只能在同一主机之间完成多个进程间的通信方式,是最原始的套接字通信模型
2> 由于不需要借助网络,所以在通信时,无需使用ip地址和端口号
3> 会在内核空间使用 套接字文件 进行通信
4> bcd-lsp 中的s,说的就是套接字文件类型
5> socket函数的说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 功能:创建一个用于通信的端点,并返回该通信对应的文件描述符,描述符使用最小未分配原则 参数1:通信域对应的协议族 AF_UNIX, AF_LOCAL Local communication(本地通信) unix(7) man 7 unix可以查看相信信息 AF_INET IPv4 Internet protocols(IPv4通信) ip(7) man 7 ip可以查看相信信息 AF_INET6 IPv6 Internet protocols(IPv6通信) ipv6(7) man 7 ipv6可以查看相信信息 参数2:指定通信语义,理解成传输方式 SOCK_STREAM 提供支持TCP通信 SOCK_DGRAM 提供支持UDP通信 SOCK_RAW 通过原始的套接字通信 参数3:通信协议,如果参数2指定了确定的通信方式,该参数填0即可 如果不确定通信方式,可用的参数有: TCP:IPPROTO_TCP UDP:IPPROTO_UDP 返回值:成功返回套接字文件描述符,失败返回-1并置位错误码
|
二、流式域套接字
1> 基于TCP通信原理,面向连接的通信方式
2> bind函数,只能绑定一个不存在的套接字文件,如果绑定的套接字文件存在,则bind函数报错:Address already in use
3> 对于客户端而言,如果不绑定一个套接字文件,系统不会给客户端绑定套接字文件
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
| #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能:给指定的套接字文件描述符绑定IP地址和端口号 参数1:要绑定的套接字文件描述符 参数2:地址信息结构体,包含了通信域、IP地址、端口号 struct sockaddr { sa_family_t sa_family; char sa_data[14]; } 以上结构体是通用地址信息结构体,无论TCP还是UDP都可以使用,主要用于形参的强制类型转换,避免出现编译报错,但是具体的通信族有不同的地址信息结构体 对于IPv4通信,需要man 7 ip进行查看 struct sockaddr_in { sa_family_t sin_family; 通信域 in_port_t sin_port; 端口号,网络字节序 struct in_addr sin_addr; 网络地址,是一个结构体 }; struct in_addr { uint32_t s_addr; IP地址,网络字节序 }; 对于本地的通信,需要man 7 unix查看 struct sockaddr_un { sa_family_t sun_family; 标识域套接字 char sun_path[108]; 套接字文件的名字 }; 参数3:参数2的大小 返回值: 成功返回0,失败返回-1并置位错误码
|
3> 判断文件是否存在函数:access
1 2 3 4 5 6 7 8 9 10 11
| #include <unistd.h> int access(const char *pathname, int mode); 功能:判断给定的文件是否具有给定的权限 参数1:要检测的文件,是一个文件路径 参数2:要检测的权限 R_OK:判断是否具有读权限 W_OK:判断是否具有写权限 X_OK:判断是否具有可执行权限 F_OK:判断是否存在 返回值:如果检查的权限存在,则返回0,否则返回-1并置位错误码
|
4> 删除文件系统中某个文件的函数:unlink
1 2 3 4 5 6
| #include <unistd.h> int unlink(const char *path); 功能:删除指定的文件 参数:要删除的文件文件路径 返回值:成功返回0,失败返回-1并置位错误码
|
2.1 流式域套接字服务器端实现
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #include<myhead.h> int main(int argc, const char *argv[]) { int sfd = socket(AF_UNIX, SOCK_STREAM, 0); if(sfd == -1) { perror("socket error"); return -1; } if(access("./unix", F_OK) == 0) { if(unlink("./unix")==-1) { perror("unlink error"); return -1; } } struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, "./unix"); if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) == -1) { perror("bind error"); return -1; } printf("bind success\n"); if(listen(sfd, 128) ==-1) { perror("listen error"); return -1; } struct sockaddr_un cun; socklen_t socklen = sizeof(cun); int newfd = accept(sfd, (struct sockaddr*)&cun, &socklen); if(newfd == -1) { perror("accept error"); return -1; } char buf[128] = ""; while(1) { bzero(buf, sizeof(buf)); int res = recv(newfd, buf, sizeof(buf), 0); if(res == 0) { printf("客户端已经下线\n"); break; } printf("[%s]: %s\n", cun.sun_path ,buf); } close(newfd); close(sfd); return 0; }
|
2.2 流式域套接字客户端实现
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include<myhead.h> int main(int argc, const char *argv[]) { int cfd = -1; cfd = socket(AF_UNIX, SOCK_STREAM, 0); if(cfd == -1) { perror("socket error"); return -1; } printf("cfd = %d\n", cfd); if(access("./linux", F_OK) == 0) { if(unlink("./linux")==-1) { perror("unlink error"); return -1; } } struct sockaddr_un cun; cun.sun_family = AF_UNIX; strcpy(cun.sun_path,"./linux"); if(bind(cfd, (struct sockaddr*)&cun, sizeof(cun)) == -1) { perror("bind error"); return -1; } printf("bind success\n"); struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, "./unix"); if(connect(cfd, (struct sockaddr*)&sun, sizeof(sun)) == -1) { perror("connect error"); return -1; } printf("connect success\n"); char buf[128] = ""; while(1) { bzero(buf, sizeof(buf)); printf("请输入>>>"); fgets(buf, sizeof(buf), stdin); buf[strlen(buf)-1] = 0; send(cfd, buf, sizeof(buf), 0); printf("发送成功\n"); if(strcmp(buf, "quit") == 0) { break; } } close(cfd); return 0; }
|
三、报式域套接字
1> 基于UDP面向无连接的通信方式
2> 如果客户端没有绑定套接字,系统不会为其绑定套接字文件,当服务器想要给客户端发消息时:怎么办?
3.1 报式域套接字服务器端
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include<myhead.h> int main(int argc, const char *argv[]) { int sfd = socket(AF_UNIX, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket error"); return -1; } printf("sfd = %d\n", sfd); if(access("./linux", F_OK) == 0) { if(unlink("./linux")==-1) { perror("unlink error"); return -1; } } struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, "./linux"); if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) == -1) { perror("bind error"); return -1; } char buf[128] = ""; struct sockaddr_un cun; socklen_t socklen = sizeof(cun); while(1) { bzero(buf, sizeof(buf)); recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cun, &socklen); printf("[%s]:%s\n", cun.sun_path, buf); strcat(buf, "*_*"); if(sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cun, sizeof(cun)) == -1) { perror("write error"); return -1; } printf("发送成功\n"); } close(sfd); return 0; }
|
3.2 报式域套接字客户端
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include<myhead.h> int main(int argc, const char *argv[]) { int cfd = socket(AF_UNIX, SOCK_DGRAM, 0); if(cfd == -1) { perror("socket error"); return -1; } if(access("./unix", F_OK) == 0) { if(unlink("./unix")==-1) { perror("unlink error"); return -1; } } struct sockaddr_un cun; cun.sun_family = AF_UNIX; strcpy(cun.sun_path, "./unix"); if(bind(cfd, (struct sockaddr*)&cun, sizeof(cun)) == -1) { perror("bind error"); return -1; } struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, "./linux"); char buf[128] = ""; while(1) { printf("请输入>>>"); fgets(buf, sizeof(buf), stdin); buf[strlen(buf)-1] = '\0'; sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sun, sizeof(sun)); if(strcmp(buf, "quit") == 0) { break; } recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL); printf("收到消息:%s\n", buf); } close(cfd); return 0; }
|
本章完