网络编程之本地通信

来源:互联网 发布:php 关闭call stack 编辑:程序博客网 时间:2024/06/15 07:28

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和端口
addrlen: addr的长度
3>
int listen(int sockfd, int backlog);
开始监听套接字
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
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



本地通信就这样构建了,一边发,一边收!

原创粉丝点击