桐庐县网站建设,建设银行暑期招聘网站,加盟网站建设案例欣赏,win7做网站bilibili 就业班视频搬运 p55
1.作用
本地进程通信使用。
2. 类型
2.1 面向连接的#xff0c;类似于TCP
#xff08;但不是TCP 呀#xff01;这里不需要什么协议了#xff01;#xff09;
socket函数的第二个参数填写 SOCK_STREAM
int sfd socket(AF_UNIX, SOCK_…bilibili 就业班视频搬运 p55
1.作用
本地进程通信使用。
2. 类型
2.1 面向连接的类似于TCP
但不是TCP 呀这里不需要什么协议了
socket函数的第二个参数填写 SOCK_STREAM
int sfd socket(AF_UNIX, SOCK_STREAM, 0)
2.2 面向无连接的 类似UDP socket函数的第二个参数填写 SOCK_DGRAM
man 7 unix自己查看一下
3. 结构体解析 A UNIX domain socket address is represented in the following structure: struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[108]; /* Pathname */ }; 地址结构体 第一个成员sun_familiy 就填写af_unix
第二个成员你填写你的socket文件的路径一般都是当前文件夹下 “./你起的名字” 就行了
千万别事先创建
4.第一次有瑕疵的代码 4.1 有瑕疵的服务器代码 后面改
//本地socket通信 服务端代码
//local1SERFile 是我自己写的结构体地址的文件路径
//你可以随意命名 但记住这个名字#include sys/types.h
#include sys/socket.h
#include sys/un.h
#include unistd.h
#include stdlib.h
#include stdio.h
#include ctype.hint main(){//创建socket描述符int sfd socket(AF_UNIX, SOCK_STREAM, 0);if (sfd0){perror( socket wrong\n);return -1;}//建立服务器的地址结构体/* struct sockaddr_un {sa_family_t sun_family; AF_UNIX char sun_path[108]; Pathname }; */struct sockaddr_un serad; serad.sun_family AF_UNIX; strcpy(serad.sun_path, ./local1SERFile); //绑定 注意结构体的成员不一样bind(sfd,(struct sockaddr*)serad, sizeof(serad));//listenlisten(sfd,128);//建立客户端地址clienad;struct sockaddr_un clienad; //注意客户端的地址成员不用你写了socklen_t clilen sizeof(clienad);//接受客户端的连接/这里应该不是高并发。 int newfd accept(sfd, (struct sockaddr*)clienad, clilen);if (newfd0) {perror(accept error\n);}char buf[1024]; while (1){//read writememset (buf, 0x00, sizeof(buf));int n read (newfd, buf, sizeof(buf));if (n0 ){printf(读到0个字符客户断线\n); break;}//大小写转换并且返回给客户端for (int i0;in;i){buf[i] toupper(buf[i]);}write (newfd, buf, n);}
close(newfd);
close (sfd);
return 0;
} 4.2 如何测试
gcc -o local1 local1.c
我把这个服务器代码编译成可执行文件local1
./local1 回车服务端开始执行
开启一个新终端 nc -U ./local1SERFile 注意这个最后的文件名是我写进代码里的结构体的自定义的socket文件的名字你写你自己的
然后就可以通信了
命令netstat -anp | grep local local换成你自己编译的最终可执行文件名查看网络状态
5. 改进
上面代码是不完善的现在展示出错
现在我们ctrlC 退出客户端过去服务端那边终端一看服务端也自动退出了。符合预期。
但是重启客户端./local1 的时候反复报错
accept error : Invalid argument 读到0个字符客户断线
这是什么问题因为前面说了
bind函数的地址参数里如果文件已经存在那么久报错
看来是bind 函数报错不是accept函数报错。 #include int unlink(const char *pathname); 参数
pathname指向需解除连接的文件名。
返回说明
成功执行时返回0。失败返回-1errno被设置。
注意只能对文件起作用
这个函数不是直接删除文件是删除硬链接直到指向这个文件的硬链接1 的时候再执行这个函数就是真的 删掉了文件内容了
那么就在你的服务端代码第一行添上这句吧 经过添加unlink后服务端和客户端又可以工作了
此时 用命令netstat -anp | grep local
(这个Local是因为我的最后编译成的可执行文件就叫local2 这样就能找到我的进程了你写你自己的文件名字
看到客户端和服务器端的状态是
unix 3 [ ] STREAM CONNECTED 70827 6223/./local2 ./local2FILE unix 2 [ ACC ] STREAM LISTENING 70826 6223/./local2 ./local2FILE
6. 客户端代码
这样就不用nc 命令测试了
6.1 客户端代码里没有bind
这里服务器代码又小改了一下所以都展示上
//本地socket通信 服务端代码
//ser.sock 是结构体地址的文件路径
#include sys/types.h
#include sys/socket.h
#include sys/un.h
#include unistd.h
#include stdlib.h
#include stdio.h
#include ctype.hint main(){unlink(./ser.sock);//创建socket描述符int sfd socket(AF_UNIX, SOCK_STREAM, 0);if (sfd0){perror( socket wrong\n);return -1;}//建立服务器的地址结构体struct sockaddr_un serad; serad.sun_family AF_UNIX; strcpy(serad.sun_path, ./ser.sock); //绑定 注意结构体的成员不一样bind(sfd,(struct sockaddr*)serad, sizeof(serad));//listenlisten(sfd,128);//建立客户端地址clienad;struct sockaddr_un clienad; //注意客户端的地址成员不用你写了socklen_t clilen sizeof(clienad);int newfd accept(sfd, (struct sockaddr*)clienad, clilen);if (newfd0) {perror(accept error\n);}char buf[1024]; while (1){memset (buf, 0x00, sizeof(buf));int n read (newfd, buf, sizeof(buf));printf(this is server,n%d,receive %s\n, n, buf); if (n0 ){printf(读到0个字符客户断线\n); break;}//大小写转换并且返回给客户端for (int i0;in;i){buf[i] toupper(buf[i]);}write (newfd, buf, n);}close(newfd);close (sfd);return 0;
} 客户端代码客户端没有建立自己的客户socket文件也能正常建立连接获得变成了大写的字母
//本地socket通信 客户端代码
#include sys/types.h
#include sys/socket.h
#include sys/un.h
#include unistd.h
#include stdlib.h
#include stdio.h
#include ctype.hint main(){//创建socket描述符clientfd ,cfdint cfd socket(AF_UNIX, SOCK_STREAM, 0);if (cfd0){perror(client socket wrong\n);return -1;}//想要连接的服务器的地址结构体struct sockaddr_un toserad; toserad.sun_family AF_UNIX;//注意socket文件需要跟服务端的一样 strcpy(toserad.sun_path, ./ser.sock); connect(cfd,(struct sockaddr*)toserad, sizeof(toserad));char buf[1024];int n 0; while (1){memset (buf, 0x00, sizeof(buf));//STDIN_FILENOprintf(please type in:\n);n read (STDIN_FILENO,buf,sizeof(buf));//发送数据 write (cfd, buf, n);memset(buf,0x00, sizeof(buf));//接收服务器的回馈n read (cfd, buf,sizeof(buf)); if (n0 ){printf(this is client, receive no data\n); break;}printf(this is client, receive %s\n,buf);}
close (cfd);
return 0;
}
执行
千万先启动服务端、再启动客户端
客户端 please type in: abc 你敲的abc进去 this is client, receive ABC 服务端 this is server,n4,receive abc abc后面还有一个回车所以服务端接受的是 4个字符。
6.2 客户端代码里bind了自己的客户套接字文件 服务代码跟6.1 里面一模一样不写了
客户端代码展示。编译后启动也是先服务端、再客户端、
//本地socket通信 客户端代码
//含有客户socket文件cli.sock
//这篇客户代码使用了bind函数。
#include sys/types.h
#include sys/socket.h
#include sys/un.h
#include unistd.h
#include stdlib.h
#include stdio.h
#include ctype.hint main(){//创建socket描述符clientfd ,cfdint cfd socket(AF_UNIX, SOCK_STREAM, 0);if (cfd0){perror(client socket wrong\n);return -1;}//想要连接的服务器的地址结构体struct sockaddr_un toserad; toserad.sun_family AF_UNIX;//注意socket文件需要跟服务端的一样 strcpy(toserad.sun_path, ./ser.sock); unlink (./cli.sock);struct sockaddr_un cliad;cliad.sun_family AF_UNIX;strcpy(cliad.sun_path, ./cli.sock); int ret bind(cfd,(struct sockaddr*)cliad, sizeof(cliad));if (ret0){perror(client bind wrong\n);return -1;}connect(cfd,(struct sockaddr*)toserad, sizeof(toserad));char buf[1024];int n 0; while (1){memset (buf, 0x00, sizeof(buf));//STDIN_FILENOprintf(please type in:\n);n read (STDIN_FILENO,buf,sizeof(buf));//发送数据 write (cfd, buf, n);memset(buf,0x00, sizeof(buf));//接收服务器的回馈n read (cfd, buf,sizeof(buf)); if (n0 ){printf(this is client, receive no data\n); break;}printf(this is client, receive %s\n,buf);}
close (cfd);
return 0;
}
执行结果跟刚才一样的
6.3 如何打印客户端地址 客户端有了自己的套接字文件的话服务端就能够找到客户端的socket文件路径。
换句话说服务端现在知道是谁哪个socket文件 在跟自己通信了
服务端的代码在accept函数后面 加一行代码 //打印客户端地址 printf(客户端地址%s\n,clienad.sun_path);