gcc ser.c -o ser
#include
#include
#include
#include
#include
#include
#define UN_SOCK_PATH "/home/admin/zzk_tenda/unix_socket/server.socket"
int main(int argc, char *argv[])
{
int sockfd, newfd, ret , recv_num, recv_num_total = 0;
char buf[50];
struct sockaddr_un server_addr;
remove(UN_SOCK_PATH);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, UN_SOCK_PATH);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
}
else
printf("socket\n");
ret = bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(server_addr));
if (ret < 0)
{
perror("bind");
}
else
printf("bind\n");
ret = listen(sockfd, 4);
if (ret < 0)
{
perror("listen");
}
else
printf("listen\n");
newfd = accept(sockfd, NULL, NULL);
if (newfd < 0)
{
perror("accept");
}
else
{
printf("accept\n");
}
while(1)
{
recv_num = recv(newfd, buf, 24, 0);
if (recv_num < 0)
{
printf("recv fail\n");
}
else if ( recv_num == 0)/* cli 断开时,recv: Success */
{
perror("recv");
return 0;
}
else
{
recv_num_total += recv_num;
printf("recv %d, content:\"%s\",总共字节%d\n",
recv_num, buf, recv_num_total);
}
}
return 0;
}
gcc cli.c -o cli
#include
#include
#include
#include
#include
#define UN_SOCK_PATH "/home/admin/zzk_tenda/unix_socket/server.socket"
int main(int argc, char *argv[])
{
int sockfd, ret, send_num, send_num_total = 0;
char buf[]="unix socketi ~~";
struct sockaddr_un server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, UN_SOCK_PATH);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket");
return -1;
}
ret = connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(server_addr));
if (ret)
{
perror("connect");
return -1;
}
while(1)
{
send_num = send(sockfd, buf, sizeof(buf), MSG_DONTWAIT);
if (send_num < 0)
{
printf("send fail\n");
}
else
{
send_num_total += send_num;
printf("send %d, content %s, send total %d\n",
send_num, buf, send_num_total);
}
sleep(2);
}
return 0;
}
在这里发现代码有一些bug,比如当终止client服务时,server端还是会显示,调用recv函数成功。如下所示
查看recv函数的用法可以发现:
当应用程序调用recv函数时,
(1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
(2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以 在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),
recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。
上述情况属于网络中断,recv返回的是0。因此只要加上一个判断,当recv返回的数据是0时,则显示网络断开即可。