网络编程之本地通信

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



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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值