? ? ?socket進程通信與網絡通信使用的是統一套接口,只是地址結構與某些參數不同。
一。創建socket服務端的流程如下:
(1)創建socket,類型為AF_LOCAL或AF_UNIX,表示用于進程通信:
[cpp]?view plain?copy
int?server_fd;??
int?client_fd;//client?file?descriptor??
struct?sockaddr_un?server_addr;???
struct?sockaddr_un?client_addr;??
size_t?server_len,client_len;??
//cteate?server?socket??
//delete?old?socket?file??
unlink(SERVER_NAME);??
if?((server_fd?=?socket(AF_UNIX,??SOCK_STREAM,??0))?==?-1)?{??
perror("socket");??
exit(1);??
}??
(2)命名socket。這里面有一個很關鍵的東西,socket進程通信命名方式有兩種。一是普通的命名,socket會根據此命名創建一個同名的socket文件,客戶端連接的時候通過讀取該socket文件連接到socket服務端。這種方式的弊端是服務端必須對socket文件的路徑具備寫權限,客戶端必須知道socket文件路徑,且必須對該路徑有讀權限。另外一種命名方式是抽象命名空間,這種方式不需要創建socket文件,只需要命名一個全局名字,即可讓客戶端根據此名字進行連接。后者的實現過程與前者的差別是,后者在對地址結構成員sun_path數組賦值的時候,必須把第一個字節置0,即sun_path[0] = 0,下面用代碼說明:
第一種方式:
[cpp]?view plain?copy
//name?the?server?socket???
server_addr.sun_family?=?AF_UNIX;??
strcpy(server_addr.sun_path,SERVER_NAME);??
server_len?=?sizeof(struct?sockaddr_un);??
client_len?=?server_len;??
第二種方式:
[cpp]?view plain?copy
//name?the?socket??
server_addr.sun_family?=?AF_UNIX;??
strcpy(server_addr.sun_path,?SERVER_NAME);??
server_addr.sun_path[0]=0;??
//server_len?=?sizeof(server_addr);??
server_len?=?strlen(SERVER_NAME)??+?offsetof(struct?sockaddr_un,?sun_path);??
其中,offsetof函數在#include 頭文件中定義。因第二種方式的首字節置0,我們可以在命名字符串SERVER_NAME前添加一個占位字符串,例如:
[cpp]?view plain?copy
#define?SERVER_NAME?@socket_server??
前面的@符號就表示占位符,不算為實際名稱。
或者可以把第二種方式的實現封裝成一個函數:
[cpp]?view plain?copy
int?makeAddr(const?char*?name,?struct?sockaddr_un*?pAddr,?socklen_t*?pSockLen)??
{??
int?nameLen?=?strlen(name);??
if?(nameLen?>=?(int)?sizeof(pAddr->sun_path)?-1)??/*?too?long??*/??
return?-1;??
pAddr->sun_path[0]?=?'\0';??/*?abstract?namespace?*/??
strcpy(pAddr->sun_path+1,?name);??
pAddr->sun_family?=?AF_UNIX;??
*pSockLen?=?1?+?nameLen?+?offsetof(struct?sockaddr_un,?sun_path);??
return?0;??
}??
像下面這樣使用這個函數:
[cpp]?view plain?copy
makeAddr("server_socket",?&server_addr,?&server_len);??
提示:客戶端連接服務器的時候,必須與服務端的命名方式相同,即如果服務端是普通命名方式,客戶端的地址也必須是普通命名方式;如果服務端是抽象命名方式,客戶端的地址也必須是抽象命名方式。
(3)綁定并偵聽
[cpp]?view plain?copy
bind(server_sockfd,?(struct?sockaddr?*)&server_addr,?server_len);??
//listen?the?server??
listen(server_sockfd,?5);??
(4)等待客戶端連接,并讀寫數據。
[cpp]?view plain?copy
while(1){??
printf("server?waiting...\n");??
//accept?client?connect??
client_len?=?sizeof(client_addr);??
client_sockfd?=?accept(server_sockfd,(struct?sockaddr*)&client_addr,?&client_len);??
//read??data?from?client?socket??
read(client_sockfd,?&ch,?1);??
printf("read?from?client?%d:?%c",client_sockfd,ch);??
ch?++;??
write(client_sockfd,?&ch,?1);??
close(client_sockfd);??
usleep(100);//1000?miliseconds?=?1?second??
}??
二 socket客戶端創建流程
(1)創建socket
(2)命名socket
(3)連接到服務端:
[cpp]?view plain?copy
//connect?to?server??
result?=?connect(sockfd,?(struct?sockaddr*)&address,?len);??
(4)與服務端進行通信
[cpp]?view plain?copy
//communicate?with?server?socket??
while(1)??
{??
printf("set?send?content:");??
scanf("%c",&ch);??
write(sockfd,?&ch,?1);??
printf("send?to?server:%c?\n",ch);??
read(sockfd,?&ch,?1);??
printf("read?from?server:?%c\n",?ch);??
}??
完整代碼如下:
(1)服務端server.c:
[cpp]?view plain?copy
#include??
#include??
#include??
#include??
#include??
#include??
#include???
#define?SERVER_NAME?"@server_socket"??
/*?
*?Create?a?UNIX-domain?socket?address?in?the?Linux?"abstract?namespace".?
*?
*?The?socket?code?doesn't?require?null?termination?on?the?filename,?but?
*?we?do?it?anyway?so?string?functions?work.?
*/??
int?makeAddr(const?char*?name,?struct?sockaddr_un*?pAddr,?socklen_t*?pSockLen)??
{??
int?nameLen?=?strlen(name);??
if?(nameLen?>=?(int)?sizeof(pAddr->sun_path)?-1)??/*?too?long??*/??
return?-1;??
pAddr->sun_path[0]?=?'\0';??/*?abstract?namespace?*/??
strcpy(pAddr->sun_path+1,?name);??
pAddr->sun_family?=?AF_UNIX;??
*pSockLen?=?1?+?nameLen?+?offsetof(struct?sockaddr_un,?sun_path);??
return?0;??
}??
int?main()??
{??
int?server_sockfd,?client_sockfd;??
socklen_t?server_len,?client_len;??
struct?sockaddr_un?server_addr;??
struct?sockaddr_un?client_addr;??
char?ch;??
int?nread;??
//delete?the?old?server?socket??
//unlink("server_socket");??
//create?socket??
server_sockfd?=?socket(AF_UNIX,?SOCK_STREAM,?0);??
//name?the?socket??
server_addr.sun_family?=?AF_UNIX;??
strcpy(server_addr.sun_path,?SERVER_NAME);??
server_addr.sun_path[0]=0;??
//server_len?=?sizeof(server_addr);??
server_len?=?strlen(SERVER_NAME)??+?offsetof(struct?sockaddr_un,?sun_path);??
//makeAddr("server_socket",?&server_addr,?&server_len);??
bind(server_sockfd,?(struct?sockaddr?*)&server_addr,?server_len);??
//listen?the?server??
listen(server_sockfd,?5);??
client_sockfd?=?-1;??
client_len?=?sizeof(client_addr);??
while(1){??
printf("server?waiting...\n");??
//accept?client?connect??
if(client_sockfd?==?-1){??
client_sockfd?=?accept(server_sockfd,(struct?sockaddr*)&client_addr,?&client_len);??
}??
//read??data?from?client?socket??
nread?=?read(client_sockfd,?&ch,?1);??
if(nread?==?0){//client?disconnected??
printf("client?%d?disconnected\n",client_sockfd);??
client_sockfd?=?-1;??
}??
else{??
printf("read?from?client?%d:?%c\n",client_sockfd,ch);??
ch?++;??
write(client_sockfd,?&ch,?1);??
}??
usleep(100);//1000?miliseconds?=?1?second??
}??
return?0;??
}??
(2)客戶端client.c
[cpp]?view plain?copy
#include??
#include??
#include??
#include??
#include??
#include??
#include???
#define?SERVER_NAME?"@server_socket"??
/*?
*?Create?a?UNIX-domain?socket?address?in?the?Linux?"abstract?namespace".?
*?
*?The?socket?code?doesn't?require?null?termination?on?the?filename,?but?
*?we?do?it?anyway?so?string?functions?work.?
*/??
int?makeAddr(const?char*?name,?struct?sockaddr_un*?pAddr,?socklen_t*?pSockLen)??
{??
int?nameLen?=?strlen(name);??
if?(nameLen?>=?(int)?sizeof(pAddr->sun_path)?-1)??/*?too?long??*/??
return?-1;??
pAddr->sun_path[0]?=?'\0';??/*?abstract?namespace?*/??
strcpy(pAddr->sun_path+1,?name);??
pAddr->sun_family?=?AF_UNIX;??
*pSockLen?=?1?+?nameLen?+?offsetof(struct?sockaddr_un,?sun_path);??
return?0;??
}??
int?main()??
{??
int?sockfd;??
socklen_t?len;??
struct?sockaddr_un?address;??
int?result;??
char?ch?=?'A';??
//create?socket???
sockfd?=?socket(AF_UNIX,?SOCK_STREAM,?0);??
//name?the?server?socket??
//makeAddr("server_socket",?&address,?&len);??
address.sun_family?=?AF_UNIX;??
strcpy(address.sun_path,?SERVER_NAME);??
address.sun_path[0]=0;??
//len?=?sizeof(address);??
len?=??strlen(SERVER_NAME)??+?offsetof(struct?sockaddr_un,?sun_path);??
//connect?to?server??
result?=?connect(sockfd,?(struct?sockaddr*)&address,?len);??
if(result?==?-1)??
{??
perror("opps:client1");??
exit(1);??
}??
//communicate?with?server?socket??
while(1)??
{??
printf("set?send?content:");??
scanf("%c",&ch);??
write(sockfd,?&ch,?1);??
printf("send?to?server:%c?\n",ch);??
read(sockfd,?&ch,?1);??
printf("read?from?server:?%c\n",?ch);??
}??
exit(0);??
} ?
?
評論
查看更多