socket的地址數據結構根據不同的系統以及網絡環境有不同形式。爲了使不同格式地址能夠被傳入套接字函數,必須強制將地址結構轉換爲:
- struct sockaddr{
- sa_family_t sa_family; /* address family*/
- char sa_data[]; /* variable-length address*/
- ...
- };
struct sockaddr{
sa_family_t sa_family; /* address family*/
char sa_data[]; /* variable-length address*/
...
};
套接字實現可以自由地添加額外的成員並且定義sa_data成員的大小。例如在linux中,該結構定義如下
- struct sockaddr{
- sa_family_t sa_family; /* address family*/
- char sa_data[14]; /* variable-length address*/
- };
struct sockaddr{
sa_family_t sa_family; /* address family*/
char sa_data[14]; /* variable-length address*/
};
其中sa_family_t表示套接字的通信域。主要有以下四個值
域 | 描述 |
AF_INET | IPv4因特網域 |
AF_INET6 | IPv6因特網域 |
AF_UNIX | UNIX域 |
AF_UNSPEC | 未指定 |
創建套接字的函數如下
- #include <sys/socket.h>
- int socket(int domain, int type, int protocol);/*成功返回文件(套接字)描述符,出錯返回-1
#include <sys/socket.h>
int socket(int domain, int type, int protocol);/*成功返回文件(套接字)描述符,出錯返回-1
其中domain指代通信域,type指代套接字類型,主要有以下四種
類型 | 描述 |
SOCK_DGRAM | 長度固定的、無連接的不可靠報文傳遞 |
SOCK_RAM | IP協議的數據報接口 |
SOCK_SEQPACKET | 長度固定、有序、可靠的面向連接報文傳遞 |
SOCK_STREAM | 有序、可靠、雙向的面向連接字節流 |
參數protocol通常是零,表示按給定的域和套接字類型選擇默認協議。當對同一域和套接字類型支持多個協議時,可以使用protocol參數選擇一個特定協議。
一個多進程間利用UNIX域套接字(只用在本地)進行通信的例子(代碼分兩部分不方便觀察,後面socket_unix.c將其合爲了一部分)
- /*
- domain_socket.h
- @Author: duanjigang @2006-4-11
- @Desp: declaratin of methods used for unix-domain-socket communication
- */
- #ifndef _H_
- #define _H_
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/un.h>
- #include <sys/socket.h>
- #define MSG_SIZE 1024
- int init_send_socket(struct sockaddr_un * addr,char * path)
- {
- int sockfd,len;
- sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
- if(sockfd<0)
- {
- exit(1);
- }
- bzero(addr,sizeof(struct sockaddr_un));
- addr->sun_family=AF_UNIX;
- strcpy(addr->sun_path,path);
- return sockfd;
- }
- int init_recv_socket(char * path)
- {
- int sockfd,len;
- struct sockaddr_un addr;
- sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
- if(sockfd<0)
- {
- return -1;
- }
- bzero(&addr,sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, path);
- unlink(path);
- len = strlen(addr.sun_path) + sizeof(addr.sun_family);
- if(bind(sockfd,(struct sockaddr *)&addr,len)<0)
- {
- return -1;
- }
- return sockfd;
- }
- int receive_from_socket(int sockfd, char msg[])
- {
- int n;
- memset(msg, 0, MSG_SIZE);
- n=recvfrom(sockfd, msg, MSG_SIZE, 0, NULL, NULL);
- if(n<=0)
- {
- return -1;
- }
- msg[n]=0;
- return n;
- }
- int send_to_socket(int sockfd, char msg[], const struct sockaddr_un * addr)
- {
- int len;
- len = strlen(addr->sun_path)+sizeof(addr->sun_family);
- sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)addr,len);
- return 1;
- }
- #endif
/*
domain_socket.h
@Author: duanjigang @2006-4-11
@Desp: declaratin of methods used for unix-domain-socket communication
*/
#ifndef _H_
#define _H_
#include <stdio.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
#define MSG_SIZE 1024
int init_send_socket(struct sockaddr_un * addr,char * path)
{
int sockfd,len;
sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
if(sockfd<0)
{
exit(1);
}
bzero(addr,sizeof(struct sockaddr_un));
addr->sun_family=AF_UNIX;
strcpy(addr->sun_path,path);
return sockfd;
}
int init_recv_socket(char * path)
{
int sockfd,len;
struct sockaddr_un addr;
sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
if(sockfd<0)
{
return -1;
}
bzero(&addr,sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
unlink(path);
len = strlen(addr.sun_path) + sizeof(addr.sun_family);
if(bind(sockfd,(struct sockaddr *)&addr,len)<0)
{
return -1;
}
return sockfd;
}
int receive_from_socket(int sockfd, char msg[])
{
int n;
memset(msg, 0, MSG_SIZE);
n=recvfrom(sockfd, msg, MSG_SIZE, 0, NULL, NULL);
if(n<=0)
{
return -1;
}
msg[n]=0;
return n;
}
int send_to_socket(int sockfd, char msg[], const struct sockaddr_un * addr)
{
int len;
len = strlen(addr->sun_path)+sizeof(addr->sun_family);
sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)addr,len);
return 1;
}
#endif
- /*
- main.c
- @Author: duanjigang @ 2006-4-11
- @Desp: Two processes communicate with unix domain socket
- */
- #include "domain_socket.h"
- #define PATH "/home/useless"
- /*
- 進程間通過域進行通訊-舉例:父子進程,一個發送,一個接收
- */
- int main(void)
- {
- int pid;
- /*
- 子進程用於發送消息
- */
- if((pid = fork()) == 0)
- {
- int fd, counter = 0;
- char send_buffer[MSG_SIZE];
- struct sockaddr_un addr;
- if( (fd = init_send_socket(&addr, PATH)) > 0)
- while(1)
- {
- memset(send_buffer, 0 , MSG_SIZE);
- /*
- 防止計數器越界,所以做一個復位判斷
- */
- sprintf(send_buffer,"message for %d times",counter++ >= 10000 ? 1 : counter);
- send_to_socket(fd, send_buffer, &addr);
- printf("Sender: %s\n", send_buffer);
- sleep(1);
- }
- }/*
- 父進程用於接收消息
- */
- else
- {
- int fd;
- char recv_buffer[MSG_SIZE];
- if( (fd = init_recv_socket(PATH))> 0)
- while(1)
- {
- memset(recv_buffer, 0, MSG_SIZE);
- if(receive_from_socket(fd, recv_buffer))
- {
- printf("Receiver: %s\n", recv_buffer);
- }
- }
- }
- }
/*
main.c
@Author: duanjigang @ 2006-4-11
@Desp: Two processes communicate with unix domain socket
*/
#include "domain_socket.h"
#define PATH "/home/useless"
/*
進程間通過域進行通訊-舉例:父子進程,一個發送,一個接收
*/
int main(void)
{
int pid;
/*
子進程用於發送消息
*/
if((pid = fork()) == 0)
{
int fd, counter = 0;
char send_buffer[MSG_SIZE];
struct sockaddr_un addr;
if( (fd = init_send_socket(&addr, PATH)) > 0)
while(1)
{
memset(send_buffer, 0 , MSG_SIZE);
/*
防止計數器越界,所以做一個復位判斷
*/
sprintf(send_buffer,"message for %d times",counter++ >= 10000 ? 1 : counter);
send_to_socket(fd, send_buffer, &addr);
printf("Sender: %s\n", send_buffer);
sleep(1);
}
}/*
父進程用於接收消息
*/
else
{
int fd;
char recv_buffer[MSG_SIZE];
if( (fd = init_recv_socket(PATH))> 0)
while(1)
{
memset(recv_buffer, 0, MSG_SIZE);
if(receive_from_socket(fd, recv_buffer))
{
printf("Receiver: %s\n", recv_buffer);
}
}
}
}
運行結果示例:
- Sender: message for 1 times
- Sender: message for 2 times
- Receiver: message for 2 times
- Sender: message for 3 times
- Receiver: message for 3 times
- Sender: message for 4 times
- Receiver: message for 4 times
- Sender: message for 5 times
- Receiver: message for 5 times
Sender: message for 1 times
Sender: message for 2 times
Receiver: message for 2 times
Sender: message for 3 times
Receiver: message for 3 times
Sender: message for 4 times
Receiver: message for 4 times
Sender: message for 5 times
Receiver: message for 5 times
socket_unix.c
- //利用UNIX域套接字通信
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/un.h>
- #include <sys/socket.h>
- #define MSG_MAX_SIZE 1024
- #define PATH "a.socket"//套接字文件
- int main()
- {
- int len;
- int socket_fd;
- struct sockaddr_un addr;
- bzero(&addr, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, PATH);
- len = strlen(addr.sun_path)+sizeof(addr.sun_family);
- if(!fork())//子進程內部代碼
- {
- int counter = 0;
- char send_buffer[MSG_MAX_SIZE];
- //init send socket
- socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if(socket_fd<0)
- {
- printf("client socket error!");
- return 0;
- }
- while(1) //循環發送數據消息
- {
- memset(send_buffer, 0, MSG_MAX_SIZE);
- sprintf(send_buffer, "message for %d times", counter++);
- //將數據信息發送到addr指定的套接字文件之中,所以這樣進程之間就可以進行通信
- sendto(socket_fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr*)&addr, len);
- printf("sender:%s\n", send_buffer);
- sleep(1);
- }
- }
- else
- {
- char recv_buffer[MSG_MAX_SIZE];
- //init recv socket
- socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if(socket_fd<0)
- {
- printf("server socket error!");
- return 0;
- }
- unlink(PATH);//防止要創建的socket文件已存在
- if(bind(socket_fd, (struct sockaddr *)&addr, len)<0)//只有bind以後纔會在硬盤創建套接字PATH
- {
- printf("bind error");
- return 0;
- }
- while(1)//循環接收數據
- {
- memset(recv_buffer, 0, MSG_MAX_SIZE);
- //receive from socket從指定socket中讀取數據,這裏socket已經綁定了指定的PATH的文件
- recvfrom(socket_fd, recv_buffer, MSG_MAX_SIZE, 0, NULL, NULL);
- printf("receive Message: %s\n", recv_buffer);
- }
- }
- return 0;
- }