C - UNIX Socket

使用 “檔案” 方式建立連線


接口函式定義


#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol); // 建立接口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // 綁定位址、埠號...
int listen(int sockfd, int backlog); // 建立server監聽
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); // 監聽serverclient連線
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// client連線到server

 讀寫等待函式定義


#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
// 等待讀寫動作
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
void FD_ZERO(fd_set *set); // 清除
void FD_SET(int fd, fd_set *set); // 設定



UNIX Server 範例


struct sockaddr_un server, client;
int server_s = 0;
int s_len, c_len;
struct timeval timeout;
fd_set set;

memset(&server, '\0', sizeof(struct sockaddr_un));
memset(&client, '\0', sizeof(struct sockaddr_un));
c_len = sizeof(client);

if ((server_s = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
unlink(UNIX_SOCKET_PATH);

server.sun_family = AF_UNIX;
strcpy(server.sun_path, UNIX_SOCKET_PATH);
s_len = sizeof(server);

if (bind(server_s, (struct sockaddr *)&server, s_len) != -1) {
chmod(server.sun_path, 0x777);

if (listen(server_s, MAX_CONNECT_CLIENT) != -1) {
while(1) {
FD_ZERO(&set);
FD_SET(server_s, &set);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
rv = select(server_s + 1, &set, NULL, NULL, &timeout);
if(rv < 0) { /* error */
break;
} else if(rv == 0) { /* timeout */
continue;
}

if ((client_s = accept(server_s, (struct sockaddr *)&client, (socklen_t *)&c_len)) == -1) {
syslog(1, "(unix_server) accept fail %d, %s", errno, strerror(errno));
if(errno == 24) { // 24, Too many open files
sleep(1);
continue;
} else {
break;
}
}

while((readBytes = my_read((void *)client_s, &cmd)) > 0) {
my_write((void *) client_s, buf);
}
}
}
}
close(server_s);
}



UNIX Client 範例


struct sockaddr_un client;
long client_s;
char *string = NULL;
int len, retryCount = 0;

memset(&client, '\0', sizeof(struct sockaddr_un));

if ((client_s = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
client.sun_family = AF_UNIX;
strcpy(client.sun_path, UNIX_SOCKET_PATH);
len = strlen(client.sun_path) + sizeof(client.sun_family);

if (connect(client_s, (struct sockaddr *)&client, len) != -1) {
if(my_write((void *)client_s, cmd) > 0) {
do {
if(my_read((void *)client_s, &string) > 0) {
syslog(1, "client recv: %s", string);
} else
syslog(1, "unix_client(%d) fd(%ld) read fail (%d, %s)", num, client_s, errno, strerror(errno));
} while(errno > 0 && ++retryCount < 1);
} else
syslog(1, "unix_client(%d) write fail (%d, %s)", num, errno, strerror(errno));
close(client_s);
}
}



共用函式

my_read 接收字串長度後,再接收字串,並給malloc分配記憶體空間(需要free)
my_write 傳送字串長度 & 字串

int my_read(long s, char **buf)
{
int intLen = sizeof(int);
int dataLen, readLen;
int len = 0;
int retryCount = 0;
char *data;
int rv;
struct timeval timeout;
fd_set set;

while(1) {
FD_ZERO(&set);
FD_SET(s, &set);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
rv = select(s + 1, &set, NULL, NULL, &timeout);
if(rv < 0) { /* error */
return rv;
} else if(rv == 0) { /* timeout */
continue;
} else {
break;
}
}

retryCount = 0;
dataLen = 0;
readLen = 0;
data = (char *)&dataLen;
do {
if((len = read(s, &data[readLen], intLen-readLen)) < 0)
break;
readLen += len;
if(!len) usleep(5);
if(!len && ++retryCount >= 1000)
break;
} while(readLen < intLen);
if(readLen != intLen)
dataLen = 0;

retryCount = 0;
readLen = 0;
if(dataLen > 0 && (*buf = malloc(dataLen+4))) {
while(readLen < dataLen) {
if((len = read(s, &(*buf)[readLen], dataLen-readLen)) < 0)
break;
readLen += len;
if(!len) usleep(5);
if(!len && ++retryCount >= 1000)
break;
}
(*buf)[readLen] = '\0';
}

return readLen;
}

int my_write(long s, char *buf)
{
int intLen = sizeof(int);
int strLen = strlen(buf);
int dataLen = strLen + intLen;
int len = -1;
char *data;
int rv;
struct timeval timeout;
fd_set set;

while(1) {
FD_ZERO(&set);
FD_SET(s, &set);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
rv = select(s + 1, NULL, &set, NULL, &timeout);
if(rv < 0) { /* error */
return rv;
} else if(rv == 0) { /* timeout */
continue;
} else {
break;
}
}

if((data = malloc(dataLen))) {
*((int *)data) = strLen;
memcpy(&data[intLen], buf, strLen);
len = write(s, data, dataLen);
free(data);
}

return len;
}


定義


#define UNIX_SOCKET_PATH "/tmp/unix.sock"
#define MAX_CONNECT_CLIENT 20




沒有留言:

張貼留言