Linux 本地socket通信
话不多说,直接上代码:
//server.c
#include <sys/socket.h>
#include <sys/un.h> // 包含本地socket的结构体
int main(){
int srv_sockfd;
srv_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un srv_addr;
struct sockaddr_un clt_addr;
/*note: use abstract namespace, the first bit of sun_path must been set 0*/
bzero(&srv_addr, sizeof(srv_addr));
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path, servername);
srv_addr.sun_path[0]=0;
int srv_len = strlen(servername) + offsetof(struct sockaddr_un, sun_path);
bind(srv_sockfd, (struct sockaddr*)&srv_addr, srv_len);
listen(srv_sockfd, 1);
int clt_len = sizeof(clt_addr);
int clt_fd = accept(srv_sockfd,(struct sockaddr*)&clt_addr, &clt_len);
if (clt_fd > 0)
{
printf("accept a connect\n");
};
struct iovec recvData[1];
//char buffer[100];
char *data = "Hello World";
recvData[0].iov_base = (void*)malloc(strlen(data));
recvData[0].iov_len = strlen(data);
while (1)
{
if (readv(clt_fd, recvData, 1) > 0){
printf("recvBuffer:%s, %d\n", recvData[0].iov_base, recvData[0].iov_len);
}
//memcpy(buffer, recvData.iov_base, recvData.iov_len);
}
}
//client.c
#include <sys/socket.h>
#include <sys/un.h> // 包含本地socket的结构体
int main()
{
int clt_fd = socket(AF_UNIX, SOCK_STREAM, 0);
int clt_len;
struct sockaddr_un client;
client.sun_family = AF_UNIX;
strcpy(client.sun_path, srevername);
client.sun_path[0]=0;
clt_len = strlen(servername) + offsetof(struct sockaddr_un, sun_path);
connect(clt_fd, (struct sockaddr *)&client, clt_len);
struct iovec sendData[1];
char *data = "Hello World";
sendData[0].iov_base = (void*)data;
sendData[0].iov_len = strlen(data);
while (1)
{
printf("SendTo:%s,%d\n", sendData[0].iov_base,strlen(data));
writev(clt_fd, sendData, 1);
}
}
其中:
—— server_name为字符串,即本次建立的socket服务的名称,客户端也是通过这个名字连接服务器的。
—— 上述是采用abstract namespace,好处是不需要知道socket服务的具体路径,可以通过名称(server_name)直接连,但是sun_path[0]必须置0,而且在赋值前,最好用bzero对服务端的sockaddr_un srv_addr进行置0。
—— listen(srv_sockfd, 1);第二个参数表征可以允许的最大连接数量。
—— int clt_fd = accept(srv_sockfd,(struct sockaddr*)&clt_addr, &clt_len);如果此时没有客户端连接,则一直处于阻塞状态。
—— 发送和接收通过writev和readv函数实现,这里发送和接受都用的是客户端节点:clt_fd。
—— readv和writev是一一对应的,服务端不写,客户端读不到,反之亦然;服务端写一次,客户端也只能读一次,否则第二次读取会阻塞,直到服务端再次写入,反之亦然。
—— 注意writev和readv的函数参数,如readv(clt_fd, recvData, 1),第一个参数为所要进行读操作的连接标识,第二个参数为读取数据的缓冲区,第三个参数为所要读取的"struct iovec"的个数。其中"struct iovec"的成员变量iov_base为真正储存数据的缓冲区,iov_length为缓冲区长度,这里需要注意的是,默认是填满一个缓冲区才会转移到下一个缓冲区,如上边,若接收的缓冲区长度大于发送的长度,则会导致重复填充以至接收缓冲区满。