socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。与流套接字不同,用类型SOCK_DGRAM指定的,它不需要建立连接和维持一个连接。本文示例代码为本地两个进程之间的通信,创建socket域为AF_UNIX。
服务端
首先服务器应用程序用系统调用socket来创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。接下来,服务器进程会给套接字起个名字(监听),使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。然
后系统调用recvfrom来接收来自客户程序发送过来的数据。如果需要,服务器程序对数据进行相应的处理,再通过系统调用sendto把处理后的数据发送回客户程序。需要特别之处的chmod函数,如果没有改变文件的属性,服务端可以获得客户端发过来的信息,但是发送回客户端将出现errno=EADV的错误。即要实现双向通信,chmod函数的调用时很有必要的。
示例代码:
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <errno.h>
int main(int argc ,char *argv[])
{
int sockfd = 0;
struct sockaddr_un addr;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
char *reply = NULL;
const int reply_size = 40;
char recv_buf[256] = "";
int reply_len = 0;
char fname[10]="tmp/test";
unlink(fname);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path,fname);
sockfd = socket(AF_UNIX,SOCK_DGRAM,0);
if(sockfd < 0 )
{
printf("socket error");
}
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
{
printf("bind error");
close(sockfd);
return 0;
}
printf("Bind is ok\n");
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
printf("chmod[ctrl_interface/ifname]");
}
res = recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr*)&from, &fromlen);
recv_buf[res] = '\0';
printf("Recv: %s\n",recv_buf);
reply = malloc(reply_size);
if (reply == NULL) {
sendto(sockfd, "FAIL\n", 5, 0, (struct sockaddr *) &from,fromlen);
printf("malloc error.\n");
return 0;
}
memset(reply,0,reply_size);
memcpy(reply, "OK.", 3);
reply_len = 3;
res = sendto(sockfd, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
printf("res=%d.errno = %d\n",res,errno);
free(reply);
close(sockfd);
}
客户端
首先客户端应用程序也是用系统调用socket来创建一个套接字,然后调用connect()连接就服务器。收发数据可用recvfrom()和sendto(),也可用recv()和send()。由于recvfrom和recv调用时阻塞的,但是我们又不想阻塞当前进程,即要用非阻塞方式调用,那么可用fcntl()来设定进程为非阻塞形式,select来查询服务端返回的信息。使用Select可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
#define PATH "tmp/test"
int main(int argc ,char *argv[])
{
int connect_fd = 0;
struct sockaddr_un addr;
int ret,res;
int flags;
char snd_buf[24],recv_buf[32];
fd_set rfds;
struct timeval tv;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path,PATH);
connect_fd = socket(AF_UNIX,SOCK_DGRAM,0);
if(connect_fd < 0)
{
printf("socket error\n");
return 0;
}
//connect server
ret=connect(connect_fd,(struct sockaddr*)&addr,sizeof(addr));
if(ret==-1)
{
printf("cannot connect to the server\n");
close(connect_fd);
return 0;
}
flags = fcntl(connect_fd, F_GETFL);
if (flags >= 0) {
flags |= O_NONBLOCK;
if (fcntl(connect_fd, F_SETFL, flags) < 0) {
printf("fcntl(ctrl->s, O_NONBLOCK)");
}
}
memset(snd_buf,0,24);
strcpy(snd_buf,"message from client");
//send info server
send(connect_fd,snd_buf,sizeof(snd_buf),0);
//read
memset(recv_buf,0,32);
for(;;){
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(connect_fd, &rfds);
res = select(connect_fd + 1, &rfds, NULL, NULL, &tv);
if (res < 0)
return res;
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(connect_fd, recv_buf, sizeof(recv_buf), 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
continue;
}
printf("ret=%d.errno = %d,receive info:%s\n",ret,errno,recv_buf);
break;
} else {
return -2;
}
}
close(connect_fd);
}