常用網絡信息檢索函數
gethostname()
getppername()
getsockname()
gethostbyname()
gethostbyaddr()
getprotobyname()
getprotobynumber()
getservbyname()
getservbyport()
網絡屬性設置
頭文件:
#include <sys/types.h>
#include <sys/socket.h>
獲取一個套接口選項
int getsockopt(
int sockfd,
int level, //選項定義的層次。支持的層次僅有SOL_SOCKET和IPPROTO_TCP和IPPROTO_IP
int optname, //需獲取的套接口選項。
void *optval, //指針,指向存放所獲得選項值的緩沖區。
socklen_t *optlen //指針,指向optval緩沖區的長度值。
);
返回值:
無錯:返回0。
出錯:返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
注釋:
getsockopt()函數用於獲取任意類型、任意狀態套接口的選項當前值,並把結果存入optval。在不同協議層上存在選項,但往往是在最高的“套接口”層次上,設置選項影響套接口的操作,諸如操作的阻塞與否、包的選徑方式、帶外數據的傳送等。被選中選項的值放在optval緩沖區中。optlen所指向的整形數在初始時包含緩沖區的長度,在調用返回時被置為實際值的長度。對SO_LINGER選項而言,相當於linger結構的大小,對其他選項來說,是一個整形數的大小。如果未進行setsockopt()調用,則getsockopt()返回系統缺省值。
設置套接口的選項
int setsockopt(
int sockfd, //標識一個套接口的描述字。
int level, //選項定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。
int optname, //需設置的選項。
const void *optval, //指向存放選項值的緩沖區的指針。
socklen_t optlen //optval緩沖區長度。
);
返回值:
無錯:返回0。
出錯:返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
注釋:
setsockopt()函數用於任意類型、任意狀態套接口的設置選項值。盡管在不同協議層上存在選項,但本函數僅定義了最高的“套接口”層次上的選項。選項影響套接口的操作,諸如加急數據是否在普通數據流中接收,廣播數據是否可以從套接口發送等等。有兩種套接口的選項:一種是布爾型選項,允許或禁止一種特性;另一種是整形或結構選項。允許一個布爾型選項,則將optval指向非零整形數;禁止一個選項optval指向一個等於零的整形數。對於布爾型選項,optlen應等於sizeof(int);對其他選項,optval指向包含所需選項的整形數或結構,而optlen則為整形數或結構的長度。SO_LINGER選項用於控制下述情況的行動:套接口上有排隊的待發送數據,且closesocket()調用已執行。



系統IO與服務器模型
在unix/linux下主要有四種I/O模型
阻塞I/O:(管道大小64K)
簡單,效率低,最常用
讀阻塞
read,readv,recv,recvfrom,recvmsg
緩沖區沒可讀數據
寫阻塞
write,writev,send,sendmag
寫緩沖區小於小於要寫入數據的量(UDP例外,無緩沖區概念)
其他:
accept,connect
非阻塞I/O:
可防止進程阻塞在I/O操作上
若請求的I/O不能馬上完成,返回錯誤。
設置非阻塞需要用循環測試文件描述符是否有數據。(poling)比較耗費CPU資源。
實現:(使用fcntl( )函數)
#include <unistd.h>
#include <fcntl.h>
int fcntl( int fd, //文件描述符
int cmd, //操作的命令
long arg //flock 結構指針
返回值 :
成功則返回0,
錯誤則返回-1,並設置errno.
例:
struct flcok
{
short int l_type;
short int l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
}
l_type 有三種狀態:
F_RDLCK 建立一個供讀取用的鎖定
F_WRLCK 建立一個供寫入用的鎖定
F_UNLCK 刪除之前建立的鎖定
l_whence 也有三種方式:
SEEK_SET 以文件開頭為鎖定的起始位置。
SEEK_CUR 以目前文件讀寫位置為鎖定的起始位置
SEEK_END 以文件結尾為鎖定的起始位置。
I/O多路復用:
允許同時控制多個I/O
思想:
構造一張有關文件描述符的表;
調用一個函數,得到這些描述符中的一個已准備好進行I/O時返回;
返回時,告訴進程的哪個描述符已經准備好,並可以進行I/O.
信號驅動I/O:
異步通信模型
I/O多路復用並發服務器流程

#include <sys/time.h>
#include <sys/types.h>
int select ( int n, //所有監控的文件描述符的集合
fd_set *readfds,// 所有要讀的文件描述符的集合
fd_set *writefds,//所有要寫的文件描述符的集合
fd_set *exceptfds,//其他要向我們通知的文件描述符
struct timeval *timeout )//超時設置。
timeout可選參數:NULL:一直阻塞,直到文件描述符就緒或出錯,0:僅僅檢測文件描述符集的狀態,然後立即返回,非0:在指定時間內,若沒事發生,則超時返回。
在我們調用select時進程會一直阻塞到有文件可以讀或有文件可以寫或超時所設置的時間到。
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
文件描述符涉及到的宏
void FD_SET(int fd, fd_set *fdset)//將FD加入到fdset
void FD_CLR(int fd, fd_set *fdset)//將fd從fdset裡面清除
void FD_ZERO(fd_set *fdset)//從fdset中清除所有的文件描述符
void FD_ISSET(int fd, fd_set *fdset)//判斷fd是否在fdset集合中
#include <sys/poll.h>
int poll ( struct pollfd *fds, //文件描述符
unsigned int nfds, //關心的事件
int timeout ) //

底層:
![]()
//select_server1.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
typedef struct sockaddr SA;
int main(int argc, char *argv[])
{
int listenfd, connfd, maxfd, i;
struct sockaddr_in servaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
fd_set rdfs, bakrdfs;
ssize_t n;
if (argc < 3)
{
fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind");
exit(-1);
}
listen(listenfd, 5);
maxfd = listenfd;
FD_ZERO(&bakrdfs);
FD_SET(listenfd, &bakrdfs);
len = sizeof(peeraddr);
while (1)
{
rdfs = bakrdfs;
if (select(maxfd+1, &rdfs, NULL, NULL, NULL) == -1)
{
perror("select");
exit(-1);
}
for (i = 0; i <= maxfd; i++)
{
if (FD_ISSET(i, &rdfs))
{
if (i == listenfd)
{
if ((connfd = accept(i, (SA *)&peeraddr, &len)) == -1)
{
perror("accept");
exit(-1);
}
fprintf(stdout, "welcome %s %d\n",
inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port));
FD_SET(connfd, &bakrdfs);
maxfd = (maxfd > connfd) ? maxfd : connfd;
}
else
{
bzero(buf, sizeof(buf));
if ((n = recv(i, buf, N, 0)) == 0)
{
close(i);
FD_CLR(i, &bakrdfs);
}
else
{
printf("n=%d %s\n", n, buf);
send(i, buf, N, 0);
}
}
}
}
}
exit(0);
}
//select_server2.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
typedef struct sockaddr SA;
int main(int argc, char *argv[])
{
int listenfd, connfd, maxfd, i;
struct sockaddr_in servaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
fd_set rdfs;
if (argc < 3)
{
fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind");
exit(-1);
}
listen(listenfd, 5);
maxfd = listenfd;
FD_ZERO(&rdfs);
while (1)
{
FD_SET(0, &rdfs);
FD_SET(listenfd, &rdfs);
if (select(maxfd+1, &rdfs, NULL, NULL, NULL) == -1)
{
perror("select");
exit(-1);
}
for (i = 0; i <= maxfd; i++)
{
if (FD_ISSET(i, &rdfs))
{
if (i == 0)
{
fgets(buf, N, stdin);
printf("*************\n");
printf("%s", buf);
}
else if (i == listenfd)
{
len = sizeof(peeraddr);
if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)
{
perror("accept");
exit(-1);
}
fprintf(stdout, "welcome %s %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
close(connfd);
}
}
}
}
exit(0);
}
//client.c
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
ssize_t n;
struct sockaddr_in servaddr;
char buf[N] = {0};
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));// "9000"---9000
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == -1)
{
perror("connect");
exit(-1);
}
printf(">");
while (fgets(buf, N, stdin) != NULL)//abc\n
{
buf[strlen(buf)-1] = 0;//abc\0
send(sockfd, buf, N, 0);
bzero(buf, sizeof(buf));
n = recv(sockfd, buf, N, 0);
printf("n=%d buf=%s\n", n, buf);
printf(">");
}
close(sockfd);
exit(0);
}
網絡超時:
超時檢測的必要性:
避免無數據時無限制的阻塞
設定的時間到時,進程從原操作返回繼續運行
TCP套接字中的recv/accept/connect
UDP套接字中的recvfrom
都會造成阻塞
三種超時檢測的方法:
1、設置socket的屬性SO_RCVTIMEO
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
voidf(int sig) {printf("*\n");}
int main(int argc, char *argv[])
{
int listenfd, connfd;
struct sockaddr_in myaddr, peeraddr;
socklen_t len;
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(atoi(argv[2]));//htons(9000)
myaddr.sin_addr.s_addr = inet_addr(argv[1]);
int on = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
perror("setsockopt");
exit(-1);
}
if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
if (listen(listenfd, 5) == -1)
{
perror("listen");
exit(-1);
}
bzero(&peeraddr, sizeof(peeraddr));
len = sizeof(peeraddr);
struct timeval t={5, 0};
if (setsockopt(listenfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1)
{
perror("setsockopt");
exit(-1);
}
while (1)
{
if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)
{
printf("%d\n", errno);
exit(-1);
}
printf("welcome %s:%d\n", inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port));
close(connfd);
}
exit(0);
}
2、用select檢測socket是否ready
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
typedef struct sockaddr SA;
int main(int argc, char *argv[])
{
int listenfd, connfd, maxfd, i;
struct sockaddr_in servaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
fd_set rdfs;
if (argc < 3)
{
fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind");
exit(-1);
}
listen(listenfd, 5);
maxfd = listenfd;
int n;
FD_ZERO(&rdfs);
while (1)
{
struct timeval t = {5, 0};
FD_SET(0, &rdfs);
FD_SET(listenfd, &rdfs);
if ((n = select(maxfd+1, &rdfs, NULL, NULL, &t)) == -1)
{
perror("select");
exit(-1);
}
printf("n=%d\n", n);
for (i = 0; i <= maxfd; i++)
{
if (FD_ISSET(i, &rdfs))
{
if (i == 0)
{
fgets(buf, N, stdin);
printf("*************\n");
printf("%s", buf);
}
else if (i == listenfd)
{
len = sizeof(peeraddr);
if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)
{
perror("accept");
exit(-1);
}
fprintf(stdout, "welcome %s %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
close(connfd);
}
}
}
}
exit(0);
}
3、設置定時器(timer),捕捉SIGALRMI信號
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
void f(int sig)
{
printf("signo=%d\n", sig);
alarm(5);
}
int main(int argc, char *argv[])
{
int listenfd, connfd;
struct sockaddr_in myaddr, peeraddr;
socklen_t len;
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(atoi(argv[2]));//htons(9000)
myaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
if (listen(listenfd, 5) == -1)
{
perror("listen");
exit(-1);
}
bzero(&peeraddr, sizeof(peeraddr));
len = sizeof(peeraddr);
// signal(SIGALRM, f);
struct sigaction act;
sigaction(SIGALRM, NULL, &act);
act.sa_handler = f;
sigaction(SIGALRM, &act, NULL);
printf("**\n");
while (1)
{
alarm(5);
if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)
{
printf("%d\n", errno);
exit(-1);
}
printf("welcome %s:%d\n", inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port));
close(connfd);
}
exit(0);
}
廣播
只有數據報(UDP協議)才能夠廣播
MAC:FF:FF:FF:FF:FF:FF
發送端
創建用戶數據報套接字
缺省創建的套接字不允許廣播數據包,需要設置屬性
接收方地址指定為廣播地址
指定端口信息
發送數據包
流程

接收端
創建用戶數據報套接字
綁定本機IP地址和端口(綁定的端口必須與發送方指定的端口相同)
等待接收數據
流程

//receiver.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in myaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(atoi(argv[2]));//6000
myaddr.sin_addr.s_addr = inet_addr(argv[1]);//0.0.0.0 192.168.1.255
if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
len = sizeof(peeraddr);
bzero(&peeraddr, sizeof(peeraddr));
while (1)
{
bzero(buf, sizeof(buf));
if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))
{
printf("errno=%d %s\n", errno, strerror(errno));
exit(-1);
}
printf("from %s:%d %s\n", inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port), buf);
}
exit(0);
}
//sender.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char buf[N] = {0};
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1)
{
perror("setsockopt");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));// 6000
servaddr.sin_addr.s_addr = inet_addr(argv[1]);//192.168.1.255
strcpy(buf, "this is a broadcast package");
while (1)
{
sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));
sleep(1);
}
close(sockfd);
exit(0);
}
組播
組播地址:224.10.10.1
MAC:01:00:5E:0A:0A:01
組播發送:
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
創建用戶數據報套接字
接收方地址指定為組播地址
指定端口信息
發送數據包
組播接收
創建用戶數據報套接字
加入多播組
綁定本機IP地址和端口(綁定的端口必須和發送方指定的端口相同)
等待接收數據
//sender.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char buf[N] = {0};
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(atoi(argv[2]));// 6000
servaddr.sin_addr.s_addr = inet_addr(argv[1]);//224.10.10.1
strcpy(buf, "this is a multicast package");
while (1)
{
sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));
sleep(1);
}
close(sockfd);
exit(0);
}
//receiver.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in myaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
struct ip_mreq mreq;
if (argc < 3)
{
fprintf(stdout, "usage:%s ip port\n", argv[0]);
exit(0);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
perror("setsockopt");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(atoi(argv[2]));//6000
myaddr.sin_addr.s_addr = inet_addr(argv[1]);//0.0.0.0 224.10.10.1
if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
len = sizeof(peeraddr);
bzero(&peeraddr, sizeof(peeraddr));
while (1)
{
bzero(buf, sizeof(buf));
if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))
{
printf("errno=%d %s\n", errno, strerror(errno));
exit(-1);
}
printf("from %s:%d %s\n", inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port), buf);
}
exit(0);
}
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq);



UNIX域套接字
特點:
常用於本地前後台進程通信
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
創建套接字是使用本地協議PF_UNIX(或者PF_LOCAL)
分為流式套接字和用戶數據報套接字
相對其他進程通信方式有使用方便,效率高的特點
本地地址結構體:
struct sockaddr_un //<sys/un.h>
{
sa_family_t sun_family;
char sun_path[108]; //套接字文件路徑
}
使用:
struct sockaddr_un myaddr;
bzero(&myaddr,sizeof(myaddr));
myaddr.sun_family = PF_UNIX;
strcpy(myaddr.sun_path,"mysocket");
UNIX域(流式)套接字
服務端
socker(PF_UNIX,SOCK_STREAM,0)
bind(,本地地址,)
listen(,)
accept(,,)
recv()/send()
……
客戶端
socker(PF_UNIX,SOCK_STREAM,0)
bind(,本地地址,)//可選
connect(, , )
recv()/send()
……
//server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <sys/un.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int listenfd, connfd;
struct sockaddr_un myaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
ssize_t n;
if ((listenfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = PF_UNIX;
strcpy(myaddr.sun_path, "serversocket");
unlink("serversocket");
if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
if (listen(listenfd, 5) == -1)
{
perror("listen");
exit(-1);
}
bzero(&peeraddr, sizeof(peeraddr));
len = sizeof(peeraddr);
while (1)
{
if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)
{
perror("accept");
exit(-1);
}
printf("welcome %s\n", peeraddr.sun_path);
while (1)
{
bzero(buf, sizeof(buf));
if ((n = recv(connfd, buf, N, 0)) == 0)
break;
send(connfd, buf, N, 0);
}
close(connfd);
}
exit(0);
}
//client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <sys/un.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
ssize_t n;
struct sockaddr_un servaddr,myaddr;
char buf[N] = {0};
if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
#if 1
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = PF_UNIX;
strcpy(myaddr.sun_path, "clientsocket");
unlink("clientsocket");
if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
#endif
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = PF_UNIX;
strcpy(servaddr.sun_path, "serversocket");
if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == -1)
{
perror("connect");
exit(-1);
}
printf(">");
while (fgets(buf, N, stdin) != NULL)//abc\n
{
buf[strlen(buf)-1] = 0;//abc\0
send(sockfd, buf, N, 0);
bzero(buf, sizeof(buf));
n = recv(sockfd, buf, N, 0);
printf("n=%d buf=%s\n", n, buf);
printf(">");
}
close(sockfd);
exit(0);
}
UNIX域(用戶數據報)套接字

//client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <sys/un.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un servaddr, myaddr;
socklen_t len;
char buf[N] = {0};
if ((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = PF_UNIX;
strcpy(myaddr.sun_path, "clientsocket");
unlink("clientsocket");
if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = PF_UNIX;
strcpy(servaddr.sun_path, "serversocket");
printf(">");
while (fgets(buf, N, stdin) != NULL)
{
buf[strlen(buf)-1] = 0;
sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));
bzero(buf, sizeof(buf));
recvfrom(sockfd, buf, N, 0, NULL, NULL);
printf("%s\n", buf);
printf(">");
}
close(sockfd);
exit(0);
}
//server.c
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <strings.h>
#include <string.h>
#include <sys/un.h>
typedef struct sockaddr SA;
#define N 64
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un myaddr, peeraddr;
socklen_t len;
char buf[N] = {0};
if ((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = PF_UNIX;
strcpy(myaddr.sun_path, "serversocket");
unlink("serversocket");
if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)
{
perror("bind");
exit(-1);
}
len = sizeof(peeraddr);
bzero(&peeraddr, sizeof(peeraddr));
while (1)
{
bzero(buf, sizeof(buf));
if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))
{
printf("errno=%d %s\n", errno, strerror(errno));
exit(-1);
}
printf("from %s: %s\n", peeraddr.sun_path, buf);
sendto(sockfd, buf, N, 0, (SA *)&peeraddr, sizeof(peeraddr));
}
exit(0);
}
作者:csdn博客 ctthuangcheng