目录
Unix域socket与TCP/IP网络socket之间的区别:
目录
Unix域socket与TCP/IP网络socket之间的区别:
-
命名socket
使用socket除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通 信,这种方式就是命名socket(Named Socket)又叫Unix域socket(Unix Domain Socket)。Unix域协议并不是一个实际的 协议族,而是在单个主机上执行客户/服务通信的一种方式,也是进程间通信(IPC)的一种方式。UNIX域数据报服务是可靠 的,不会丢失消息,也不会传递出错。它也提供了两类套接字:字节流套接字(有点像TCP)和数据报套接字(有点像UDP)。
命名socket与普通的TCP/IP网络 socket相比具有以下特点:
-
UNIX域套接字域传统套接字的区别是用路径名表示协议族的描述,ls -l看到的该文件类型为 s。
-
UNIX域套接字域TCP套接字相比,在同一台主机的传输速度前者是后者的两倍。UNIX域套接字仅仅复制数据,并不执行 协议处理,不需要添加或删除网络报头,无需计算校验和,不产生顺序号,也不需要发送确认报文 。
-
UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。
-
Unix域socket与TCP/IP网络socket之间的区别:
命名socket与TCP/IP网络socket通信使用的是同一套接口,只是地址结构与某些参数不同:TCP/IP网络socket通过IP地址和 端口号来标识,而UNIX域协议中使用普通文件系统路径名标识。所以命名socket和普通socket只是在创建socket和绑定服务器 标识的时候与网络socket有区别,具体如下:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
/*
创建一个socket,可以是TCP/IP网络socket,也是命名socket,具体由domain参数决定。该函数的返回值为生成的套接字描述符。
*/
参数说明:
domain:
指定协议族:对于命名socket/Unix域socket,其值须被置为 AF_UNIX或AF_LOCAL;如果是网络socket则其值应该 为 AF_INET; 参数type指定套接字类型,它可以被设置为 SOCK_STREAM(流式套接字)或 SOCK_DGRAM(数据报式套接字)。
protocol:
默认设置为 0。
SOCK_STREAM :
式本地套接字的通信双方均需要具有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用 struct sockaddr_un 类型的变量。
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* 路径名 */
};
-
socket的两种基本方式
-
一种是普通的命名,socket会根据此命名创建一个同名的socket文 件,客户端连接的时候通过读取该socket文件连接到socket服务端。这种方式的弊端是服务端必须对socket文件的路径具备写权 限,客户端必须知道socket文件路径,且必须对该路径有读权限。
-
另外一种命名方式是抽象命名空间,这种方式不需要创建 socket文件,只需要命名一个全局名字,即可让客户端根据此名字进行连接。后者的实现过程与前者的差别是,后者在对地址结 构成员sun_path数组赋值的时候,必须把第一个字节置0,即sun_path[0] = 0。这里第一种方式比较常见,下面的例程中我们 就使用了该方法。
-
编程示例
-
server头文件
#ifndef __SOCKET_SERVER_H
#define __SOCKET_SERVER_H
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/un.h>
#define BUF_SIZE 512
int socket_start(int domain, int type, int protocol,char* path , char* msg);
int rdwr_init(int clinefd,char *buf, char *msg);
int get_opt(int argc, char * const argv[],const char *optstring);
#endif
-
server源文件
#include "socket_server.h"
void print_usage(char *prograname)
{
printf("%s usage : \n", prograname);
printf("-p(--parh): specify sever will go to run with path.\n");
printf("-m(--msg): specify sever write msg to client.\n");
printf("-d(--daemon): specify sever will go to run with daemon.\n");
printf("-h(--help): print this help information.\n");
return ;
}
int main(int argc, char *argv[])
{
get_opt(argc,argv,"p:dm:h");
return 0;
}
int get_opt(int argc, char * const argv[],const char *optstring)
{
char* path;
int ch;
char* msg = NULL;
struct option opts[] = {
{"path", required_argument, NULL, 'p'},
{"write_msg", required_argument, NULL, 'm'},
{"daemon", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
while((ch=getopt_long(argc, argv, "p:m:dh", opts, NULL)) != -1 )
{
switch(ch)
{
case 'p':
path=optarg;
break;
case 'm':
msg = optarg;
break;
case 'd':
daemon(0,0);
break;
case 'h':
print_usage(argv[0]);
return 0;
}
}
if( !path||!msg)
{
print_usage(argv[0]);
return 0;
}
if ((socket_start(AF_UNIX, SOCK_STREAM,0, path, msg))< 0)
{
printf("socket_start error:%s\n", strerror(errno));
exit(0);
}
}
int socket_start(int domain, int type, int protocol, char* path, char *msg)
{
int lisfd = 0;
int clifd = 0;
int on = 1;
int rv = 0;
char buf[BUF_SIZE];
struct sockaddr_un serv_addr;
struct sockaddr_un cli_addr;
socklen_t len = sizeof(serv_addr);
if ((lisfd = socket(domain,type, protocol))< 0)
{
printf("Socket error:%s\a\n", strerror(errno));
return -1;
}
printf("socket[%d] successfuly!\n", lisfd);
if ( !access(path, F_OK))
{
unlink(path);
}
setsockopt(lisfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strncpy(serv_addr.sun_path, path, sizeof(serv_addr.sun_path) - 1);
if ((rv = bind(lisfd, (struct sockaddr *)&serv_addr, len)) < 0)
{
printf("Bind error %s\n", strerror(errno));
goto EXIT;
}
if ((rv = listen(lisfd, 13)) < 0)
{
printf("Listen error:%s\n", strerror(errno));
goto EXIT;
}
printf("Waiting clinet to connect.....\n");
while(1)
{
if ((clifd = accept(lisfd, (struct sockaddr *)&cli_addr, &len))< 0)
{
printf("Accept error:%s\n", strerror(errno));
goto EXIT;
}
if ((rv = rdwr_init(clifd, buf, msg)) < 0 )
{
printf("Write or read form client error:%s\n", strerror(errno));
goto EXIT;
}
}
return clifd;
EXIT:
unlink(path);
close(lisfd );
close(clifd );
return -1;
}
int rdwr_init(int clinefd,char *buf, char * msg)
{
int rv = 0;
memset(buf,0, BUF_SIZE);
while(1)
{
if ((rv = read(clinefd, buf, BUF_SIZE)) < 0)
{
printf("Read by socket[%d] error:%s\n", clinefd, strerror(errno));
goto STOP;
}
else if (0 == rv)
{
printf("The connect get disconneceted.\n");
goto STOP;
}
else if (rv > 0)
{
printf("Read %d bytes data from client, there are :%s\n", rv, buf);
}
if ((rv =write(clinefd, msg, strlen(msg))) < 0)
{
printf("write to cilent by socket[%d] error:%s \n",clinefd, strerror(errno));
goto STOP;
}
printf("Write[%s] to clinet successfuly.\n", msg);
}
STOP:
printf("The socket[%d] will eixt!\n", clinefd);
exit(0);
}
-
client源文件
#ifndef __SOCKET_CLIENT__
#define __SOCKET_CLIENT__
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/un.h>
#define MSG_STR "Hello network word! I'm client!"
#define BUF_SIZE 1024
#endif
void print_usage(char *paogname)
{
printf("%s usage : \n", paogname);
printf("-p(--path): sepcify connect path.\n");
printf("-m(--message): The message you want to send.\n");
printf("-h(--help): print this help information.\n");
return ;
}
int main (int argc, char **argv)
{
int sockfd;
int rv = -1;
struct sockaddr_un servaddr;
char* path = NULL;
char* message = NULL;
char buf[BUF_SIZE];
int ch;
int temp;
struct option opts[] = {
{"path", required_argument, NULL, 'p'},
{"message", required_argument, NULL, 'm'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
while((ch=getopt_long(argc, argv, "p:m:h", opts, NULL)) != -1 )
{
switch(ch)
{
case 'p':
path=optarg;
break;
case 'm':
message=optarg;
break;
case 'h':
print_usage(argv[0]);
return 0;
}
}
if( !path || !message )
{
print_usage(argv[0]);
return 0;
}
sockfd = socket(AF_UNIX,SOCK_STREAM,0);
if(sockfd < 0)
{
printf("Cearte socket failure :%s\a\n",strerror(errno));
return -1;
}
printf("Create socket[%d] sucessfully.\n",sockfd);
memset(&servaddr,0,sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strncpy(servaddr.sun_path, path, sizeof(servaddr.sun_path) - 1);
rv = connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
if(rv <0)
{
printf("connect toserver[%s] failure :%s\n\a",path,strerror(errno));
return -2;
}
printf("connect to server[%s] successfully!\n",path);
rv = write(sockfd,message,strlen(message));
if(rv <0)
{
printf("Write to server failure by socket[%d] failure: %s\n",sockfd,strerror(errno));
return -3;
}
else
printf("Write[%s] to server by socket[%d] successfuly!\n", message, sockfd);
memset(buf,0,sizeof(buf));
rv = read(sockfd,buf,BUF_SIZE);
if(rv < 0)
{
printf("Read to server socket[%d] failure: %s\n",sockfd,strerror(errno));
return -4;
}
else if(rv == 0)
{
printf("socket[%d] get disconnected\n",sockfd);
return -4;
}
else if(rv >0)
{
printf("Read %d bytes data form Server: %s\n",rv,buf);
}
close(sockfd);
unlink(path);
return 0;
}
-
运行结果
- 服务器端
- 客户端