IPC通信即本地进程之间的通信。
先举个简单例子吧。
服务器端代码:
1/*********************************************************************************
2 * Copyright: (C) 2017 luliteng<852335815@qq.com>
3 * All rights reserved.
4 *
5 * Filename: server.c
6 * Description: This file
7 *
8 * Version: 1.0.0(06/05/2017)
9 * Author: luliteng <852335815@qq.com>
10 * ChangeLog: 1, Release initial version on "06/05/2017 07:42:35 AM"
11 *
12 ********************************************************************************/
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <netinet/in.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18 #include <string.h>
19
20 int main(int argc, char **argv)//参数个数,参数
21 {
22 int fd = socket(AF_INET, SOCK_STREAM, 0);//创建socket,fd为socket的返回值
23 if (fd == -1)//判断对错,错误输出-1
24 {
25 perror("socket");
26 exit(-1);
27 }
28 struct sockaddr_in addr;//通信地址结构准备
29 addr.sin_family = AF_INET;//网络通信
30
31 addr.sin_port = htons(2222);//端口号
32 addr.sin_addr.s_addr = inet_addr("192.168.71.128");//ip地址
33 int res = bind(fd, (struct sockaddr*)&addr, sizeof(addr));//创建bind(),res为bind的返回值
34 if (res == -1)
35 {
36 perror("bind");
37 exit(-1);
38 }
39 printf("bind ok\n");//连接成功打印出bind ok
40 listen(fd, 100);//监听队列
41 struct sockaddr_in from;
42 socklen_t len = sizeof(from);
43 int sockfd = accept(fd, (struct sockaddr*)&from, &len);//创建accept,from是取前面地址
44 printf("%s连接了\n", inet_ntoa(from.sin_addr));
45 char buf[100] = {};
46 res = read(sockfd, buf, sizeof(buf));//把读出来的东西存到buf里面
47 printf("读到了%d字节,内容:%s\n", res, buf);
48 close(sockfd);
49 close(fd);
50 return 0;
51 }
客户端代码:
1 /*********************************************************************************
2 * Copyright: (C) 2017 luliteng<852335815@qq.com>
3 * All rights reserved.
4 *
5 * Filename: server.c
6 * Description: This file
7 *
8 * Version: 1.0.0(06/04/2017)
9 * Author: luliteng <852335815@qq.com>
10 * ChangeLog: 1, Release initial version on "06/04/2017 09:22:31 PM"
11 *
12 ********************************************************************************/
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 #include <netinet/in.h>
18
19 int main(int argc, char **argv)
20 {
21 int fd = socket(AF_INET, SOCK_STREAM, 0);
22 if (fd == -1)
23 {
24 perror("socket");
25 exit(-1);
26 }
27 struct sockaddr_in addr;
28 addr.sin_family = AF_INET;
29 addr.sin_port = htons(2222);
30 addr.sin_addr.s_addr = inet_addr("10.154.216.80");
31 int res = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
32 if (res == -1)
33 {
34 perror("connect");
35 exit(-1);
36 }
37 printf("connect ok\n");
38 write(fd, "hello", 5);
39 close(fd);
40 return 0;
41 }
网络编程的基本结构
服务器端:
1、socket
2、准备我们的通信地址结构体
3、服务器端为bind
4、监听listen
5、等待客户端连接,函数accept,返回新的描述符用于读写交互,accept相当于阻塞函数
6、读写函数
7、关闭socket
代码中用到的函数:
1>
int socket(int domain, int type, int protocol)
函数返回一个整型的socket描述符,供后面的使用,其中参数:
domain:指明使用的协议族,值
AF_INET:用于网络通信
AF_UNIX:单一Unix系统中进程间通信
type: 指明socket类型,值
SOCK_STREAM:流式,面向连接的比特流,顺序、可靠、双向,用于TCP通信
SOCK_DGRAM: 数据报式,无连接的,定长、不可靠 UDP通信
protocol:由于指定了type,这里一般用“0”
一个socket的建立:
int fd = socket(AF_INET, SOCK_STREAM, 0)
==================
intsocket(int domain,int type, int protocol)
_________________________返回值:非负描述符 – 成功,-1 - 出错
其中:
family指明了协议族/域,通常AF_INET、AF_INET6、AF_LOCAL等;
type是套接口类型,主要SOCK_STREAM、SOCK_DGRAM、SOCK_RAW;
protocol一般取为0。成功时,返回一个小的非负整数值,与文件描述符类似。
2>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
将socket和相应的IP地址、 端口绑定
sockfd: socket()返回的文件描述符
addr: 绑定的IP和端口
将socket和相应的IP地址、 端口绑定
sockfd: socket()返回的文件描述符
addr: 绑定的IP和端口
addrlen: addr的长度
3>
int listen(int sockfd, int backlog);
开始监听套接字
backlog 是未经过处理的连接请求队列可以容纳的最大数目。
即每一个连入请求都要进入一个连入请求队列,等待
listen 的程序调用accept()函数来接受这个连接。当系统还没有
调用accept()函数的时候,如果有很多连接,那么本地能够等待的最大数目就是backlog 的
即每一个连入请求都要进入一个连入请求队列,等待
listen 的程序调用accept()函数来接受这个连接。当系统还没有
调用accept()函数的时候,如果有很多连接,那么本地能够等待的最大数目就是backlog 的
数值。
4>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
开始等待客户端连过来套接字
addr 和 addrlen 一般是NULL, 否则只允许addr指定的客户端连过来。
5>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
连接指定的服务器, 其中addr指定连接服务器的IP和端口
6>
int close(int fd);
关闭socket
7>
int shutdown(int sockfd, int how);
半关闭socket
半关闭socket
how: SHUT_RD、 SHUT_WR、 SHUT_RDWR
a) SHUT_RD,关闭连接的读这一半,套接字中不再有数据可接收,而且套接字接收缓冲区中的现有数据都被丢弃,进程不能再对这样的套接字调用任何读函数。该套接字接收的来自对端的任何数据都被确认,然后悄然丢弃。
b) SHUT_WR,关闭连接的写这一半,当前留在套接字发送缓冲区的数据都将被发送掉,后跟TCP的正常连接终止序列,进程不能再对这样的套接字调用任何写函数。
c) SHUT_RDWR,连接的读半部与写半部都关闭。
若成功返回0,若出错返回-1
来个实例更深入理解IPC通信
服务器端:
1 /*********************************************************************************
2 * Copyright: (C) 2017 luliteng<luliteng@gmail.com>
3 * All rights reserved.
4 *
5 * Filename: fuwuqi1.c
6 * Description: This file
7 *
8 * Version: 1.0.0(2017年05月10日)
9 * Author: luliteng <luliteng@gmail.com>
10 * ChangeLog: 1, Release initial version on "2017年05月10日 15时58分15秒"
11 *
12 ********************************************************************************/
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <string.h>
18 #include <time.h>
19 #include <arpa/inet.h>
20 #include <signal.h>
21 int fd;
22 void fa(int signo) //用一个信号正常关闭文件描述符
23 {
24 printf("服务器即将关闭!\n");
25 sleep(2);
26 close(fd);
27 exit(0);
28 }
29 /*
30 void TIME()
31 {
32 time_t timep;
33 time(&timep);
34 printf("当前时间:%s", ctime(&timep));
35 }
36 */
37 void TIME() //一个现实当前时间的函数
38 {
39 char buf[100] = {};
40
41 time_t cur_time = time(0);
42
43 struct tm* cur = localtime(&cur_time);
44 sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", cur->tm_year+1900, cur->tm_mon+1, cur-> tm_mday, cur->tm_hour, cur->tm_min, cur-
>tm_sec);
45 printf("当前时间:%s\n", buf);
46 }
47 int main(int argc, char **argv)
48 {
49 TIME();
50
51 printf("请按ctrl+C退出服务器\n");
52
53 signal(SIGINT, fa); //发送信号关闭文件描述符
54 fd = socket(AF_INET, SOCK_STREAM, 0); //socket
55 if (fd == -1) perror("socket"), exit(-1);
56
57 struct sockaddr_in addr; //定义一系列结构体
58 addr.sin_family = AF_INET;
59
60 addr.sin_port = htons(2222);
61 addr.sin_addr.s_addr = inet_addr("192.168.71.128");
62 int reuse = 1;
63 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); //避免地址冲突
64 int res = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); //绑定
65 if (res == -1) perror("bind"), exit(-1);
66 printf("bind ok!\n");
67 listen(fd, 100); //监听
68 while(1){
69 struct sockaddr_in from;
70 socklen_t len = sizeof(from);
71 int newfd = accept(fd, (struct sockaddr*)&from, &len); //有客户连接,则返回新 的描述符
72 if (newfd == -1) perror("accept"), exit(-1);
73 printf("%s连接了\n", inet_ntoa(from.sin_addr));
74 TIME();
75 pid_t pid = fork(); //有客户来时,创建一个子进程来处理
76 if(!pid)
77 {
78 char buf[100] = {};
79 while(1){
80 res = read(newfd, buf, sizeof(buf)); //对新的描述符进行读写操作
81 TIME();
82 printf("读到了%d个字节,内容是%s\n", res, buf);
83 if (res == -1) perror("read"), exit(-1);
84 else if(!res) break;
85 if (!strcmp(buf, "byebye")) //当客户输入相应字符时,可知客户端退出了
86 {
87 printf("%s退出了\n", inet_ntoa(from.sin_addr));
88 break;
89 }
90 write(newfd, buf, strlen(buf));
91 memset(buf, 0, strlen(buf)); //清空buf
92 }
93 close(newfd); //子进程关闭新的描述符
94 exit(0);
95 }
96 close(newfd); //父进程关闭新的描述符
97 }
98 // close(fd);
99 return 0;
100 }
客户端:
1 /*********************************************************************************
2 * Copyright: (C) 2017 luliteng<luliteng@gmail.com>
3 * All rights reserved.
4 *
5 * Filename: myclient.c
6 * Description: This file
7 *
8 * Version: 1.0.0(2017年05月10日)
9 * Author: luliteng <luliteng@gmail.com>
10 * ChangeLog: 1, Release initial version on "2017年05月10日 16时10分16秒"
11 *
12 ********************************************************************************/
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <string.h>
18 #include <time.h>
19 #include <arpa/inet.h>
20 #include <time.h>
21 /* void TIME()
22 {
23 time_t timep;
24 time(&timep);
25 printf("当前时间:%s", ctime(&timep));
26 }
27 */
28 void TIME() //时间函数
29 {
30 char buf[100] = {};
31 time_t cur_time = time(0);
32 struct tm* cur = localtime(&cur_time);
33 sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", cur->tm_year+1900, cur->tm_mon+1, cur->tm_mday, cur->tm_hour, cur->tm_min, cur-
>tm_sec);
34 printf("当前时间:%s\n", buf);
35 }
36 int main(int argc, char **argv)
37 {
38 int fd = socket(AF_INET, SOCK_STREAM, 0); //socket
39 if (fd == -1) perror("socket"), exit(-1);
40 struct sockaddr_in addr; //定义结构体相关内容
41 addr.sin_family = AF_INET;
42 addr.sin_port = htons(2222);
43 addr.sin_addr.s_addr = inet_addr("192.168.71.128");
44 int res = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); //连接服务器端
45 if (res == -1) perror("connect"), exit(-1);
46 printf("connect ok!\n");
47 char buf[100] = {};
48 char buf1[100] = {};
49 while(1){
50 TIME();
51 printf("请输入聊天内容:\n");
52 scanf("%s", buf);
53 write(fd, buf, strlen(buf));
54 if (!strcmp(buf, "byebye")) break; //输入相应字符退出
55 int res = read(fd, buf1, strlen(buf1));
56 if (res == -1)
57 {
58 perror("read");
59 break;
60 }
61 printf("read:%s\n", buf1);
62 memset(buf, 0, strlen(buf));
63 memset(buf1, 0, strlen(buf1));
64 }
65 close(fd);
66
67
68 return 0;
69 }
70
通过gcc编译这两个.c文件,没有错误之后 分别运行./a.out
本地通信就这样构建了,一边发,一边收!