计算机中通信的思考(一针见血,见解深刻,待追风仔细研读)

计算机中通信的思考http://blog.csdn.net/ktigerhero3/article/details/49994397

一切皆为联系,现代计算机更是将联系发挥到极致,《终结者》中的无处不在的AI终将实现,本文总结了对象(计算机,手机,智能家居)及(进程,线程)之间的通信。

1.相同计算机不同进程间通信

不同进程间的常用通信方式: 
管道( pipe )、有名管道 (named pipe)、信号量( semophore ) 、消息队列( message queue )、信号 ( sinal ) 、共享内存( shared memory ) 
套接字( socket )

1.1父子进程通信

如图中的父进程PA与子进程CA1之间的通信 
这里写图片描述 
在一个操作系统中有很多个进程,这些进程的调度由操作系统完成。 
需要解决的问题: 
如何新建一个父进程PA和一个子进程CA1,然后父进程发送消息(“Son progress,I am father progress.”)给子进程,子进程收到消息后回答(”Father progress,I am son progress.”)?

1.2非父子进程间的通信

如图中的进程PA与进程PB之间的通信

1.2.1需要解决的问题:

如何新建进程PA和进程PB,然后进程PB发送消息(“Hello friend,I am progress PA.”)给进程PA?

1.2.2利用有名管道实现不同进程间的通信

如图为进程PA和PB利用管道进行通信的示意图: 
这里写图片描述 
(1)服务器端 
思路: 
1)创建命名管道,调用函数 CreateNamedPipe(); 
2)创建事件,绑定事件,调用CreateEvent() 
3)连接管道,等待客户端连接请求调用函数ConnectNamedPipe() 
4)使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止,调用WaitForSingleObject() 
5)当管道收到数据,读取数据,调用ReadFile() 
服务器端代码如下:

#include<windows.h>
#include<iostream>
using namespace std;
int main()
{
    //将const char*转换为LPCWSTR
    const char* charpipeName = "\\\\.\\pipe\\MyPipe";
    WCHAR pipeName[256];
    memset(pipeName, 0, sizeof(pipeName));
    MultiByteToWideChar(CP_ACP, 0, charpipeName, strlen(charpipeName) + 1, pipeName,
        sizeof(pipeName) / sizeof(pipeName[0]));
    //创建命名管道
    HANDLE hPipe = CreateNamedPipe(pipeName,
        PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
        0, 1, 1024, 1024, 0, NULL);
    if (INVALID_HANDLE_VALUE == hPipe)
    {
        cout << "创建命名管道失败!" << endl;
        hPipe = NULL;
        return 0;
    }
    //创建事件
    HANDLE hEvent;
    hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!hEvent)
    {
        cout << "创建事件对象失败!" << endl;
        CloseHandle(hPipe);
        hPipe = NULL;
        return 0;
    }
    OVERLAPPED ovlap;
    ZeroMemory(&ovlap, sizeof(OVERLAPPED));
    ovlap.hEvent = hEvent;
    //等待客户端连接请求
    if (!ConnectNamedPipe(hPipe, &ovlap))
    {
        if (ERROR_IO_PENDING != GetLastError())
        {
            cout << "等待客户端连接失败!" << endl;
            CloseHandle(hPipe);
            CloseHandle(hEvent);
            hPipe = NULL;
            return 0;
        }
    }
    //使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止
    if (WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE))
    {
        cout << "等待对象失败!" << endl;
        CloseHandle(hPipe);
        CloseHandle(hEvent);
        hPipe = NULL;
        return 0;
    }
    CloseHandle(hEvent);

    /////////////////////////////////////////读取内容
    char buf1[100];
    DWORD dwRead;
    if (!ReadFile(hPipe, buf1, 100, &dwRead, NULL))
    {
        cout << "ReadFile failed" << endl;
        return 0;
    }
    else
    {
        cout << "读取成功" << endl;
        cout << buf1 << endl;
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

(2)客户端 
思路: 
1)判断是否有命名管道实例,调用WaitNamedPipe() 
2)连接命名管道,调用CreateFile() 
3)向管道写入内容,调用WriteFile() 
客户端实现代码如下:

#include<windows.h>
#include<iostream>
using namespace std;

int main()
{
    //将const char*转换为LPCWSTR
    const char* charpipeName = "\\\\.\\pipe\\MyPipe";
    WCHAR pipeName[256];
    memset(pipeName, 0, sizeof(pipeName));
    MultiByteToWideChar(CP_ACP, 0, charpipeName, strlen(charpipeName) + 1, pipeName,
        sizeof(pipeName) / sizeof(pipeName[0]));

    HANDLE hPipe;
    //判断是否有命名管道实例
    if (!WaitNamedPipe(pipeName, NMPWAIT_WAIT_FOREVER))
    {
        cout << "当前没有可利用的命名管道实例!" << endl;
        return 0;
    }

    //连接命名管道
    hPipe = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE,
        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hPipe)
    {
        cout << "打开命名管道失败!" << endl;
        hPipe = NULL;
        return 0;
    }else
    {
        cout << "打开管道成功" << endl;
    }

    //写入内容
    char buf[100] = "Hello friend,I am progress PB.I am client progress.";
    DWORD dwWrite;
    if (!WriteFile(hPipe, buf, strlen(buf) + 1, &dwWrite, NULL))
    {
        cout << "WriteFile failed" << endl;
        return 0;
    }
    else
    {
        cout << "写入成功" << endl;
    }
    return 0;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

2.相同进程间的线程的通信

由于同一进程之间的不同线程共享进程中的代码,数据和文件,因此同一进程中线程间通信通常使用共享来通信。 
例如:

3.不同进程间的线程的通信

这个问题包括相同进程间线程的通信和不同进程间进程的通信两个问题。分别解决就实现了不同进程间线程的通信。 
每个进程都有一个主线程,进程间共享数据的最佳方法是使用内存映射文件。

3.1要解决的问题

如何通过内存映射达到两个进程PA与PB交换信息的效果?如有一段字符串“Hello friend,I am progress PA.”如何在PA与PB间共享。

3.2利用内存映射在不同进程间共享数据

不同进程通过存储器映射共享对象如图所示这里写图片描述 
如图所示,共享内存的关键是创建进程和物理存储器的映射关系。 
进程PA(实现在内存中写数据)代码 
思路 
1)创建文件 
2)创建映射 
3)在内存(即view视图)中写入需要的共享的数据 
4)取消映射 
代码如下:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
/* 预处理申明 */
#define BUF_SIZE 256
/* 全局变量 */
LPTSTR szName = TEXT("SharedFileMappingObject");
LPTSTR szMsg = TEXT("进程的消息");
void main(int argc, PCHAR argv[])
{
    //文件映射句柄
    HANDLE hMapFile;
    //共享数据缓冲区指针
    LPTSTR pBuf;
    //创建命名的文件映射,不代表任务硬盘上的文件
    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0,
        BUF_SIZE,
        szName);
    if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE)
    {
        printf("CreateFileMapping error: %d\n", GetLastError());
        return;
    }
    //创建View
    pBuf = (LPTSTR)MapViewOfFile(hMapFile,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        BUF_SIZE);
    if (pBuf == NULL)
    {
        printf("MapViewOfFile error %d\n", GetLastError());
        return;
    }
    //将共享数据复制到文件映射中,如果运行时输入了参数则使用参数
    if (argc == 1)
    {
        CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg));
    }
    else
    {
        DWORD dwCopyLen = (lstrlen(argv[1])<BUF_SIZE) ? lstrlen(argv[1]) : BUF_SIZE;
        CopyMemory((PVOID)pBuf, argv[1], dwCopyLen);
    }
    printf("运行程序,完成运行后,按任意键退出。");
    _getch();
    //取消映射,退出
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

进程PB(实现在内存中读数据)代码 
思路 
1)通过文件名打开文件映射 
2)读映射文件中的内容 
3)显示得到的共享数据 
4)关闭句柄 
代码如下:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
/* 预处理申明 */
#define BUF_SIZE 256
/* 全局变量 */
LPTSTR szName = TEXT("SharedFileMappingObject");
LPTSTR szMsg = TEXT("进程的消息");
void main(int argc, PCHAR argv[])
{
    //文件映射句柄
    HANDLE hMapFile;
    //共享数据缓冲区指针
    LPTSTR pBuf;
    //创建命名的文件映射,不代表任务硬盘上的文件
    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0,
        BUF_SIZE,
        szName);
    if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE)
    {
        printf("CreateFileMapping error: %d\n", GetLastError());
        return;
    }
    //创建View
    pBuf = (LPTSTR)MapViewOfFile(hMapFile,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        BUF_SIZE);
    if (pBuf == NULL)
    {
        printf("MapViewOfFile error %d\n", GetLastError());
        return;
    }
    //将共享数据复制到文件映射中,如果运行时输入了参数则使用参数
    if (argc == 1)
    {
        CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg));
    }
    else
    {
        DWORD dwCopyLen = (lstrlen(argv[1])<BUF_SIZE) ? lstrlen(argv[1]) : BUF_SIZE;
        CopyMemory((PVOID)pBuf, argv[1], dwCopyLen);
    }
    printf("运行程序,完成运行后,按任意键退出。");
    _getch();
    //取消映射,退出
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

4.不同计算机的通信,客户端和服务器端的通信过程

实现计算机PCA的进程pca_progress到计算机PCB中的进程pcb_progress之间的通信。 
例如:计算机PCA中的进程pca_progress,发送消息(“Hello friend,I am coputer A,my pid is pca_progress.”)给计算机PCB,PCB中的进程pcb_progress收到消息后回答(”“Hello friend,I am coputer B,my pid is pcb_progress.”)

5.手机与计算机的通信

手机和计算机的通信其实和计算机和计算机通信相类似。手机可以看做是一台装了操作系统(Android系统,IOS系统)的计算机。Android系统架构为四层结构,从上层到下层分别是应用程序层、应用程序框架层、系统运行库层以及Linux内核层。 
因此,安卓手机和PC通信同样采用socket通信。 
(1)理解socket 
计算机网络体系结构如图 
这里写图片描述 
而 socket是在应用层和传输层之间的一个抽象层,它把网络层和传输层各种复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。 
如下图表示了socket抽象。 
这里写图片描述
思路如下: 
(1)PC端(服务器端)socket 
系统如果为linux,则可以采用linux系统下的系统调用函数直接创建服务器端。linux系统下包括<sys/socket.h>利用创建套接字的标准流程新建一个服务器端套接字。 
系统如果是windows,这调用windows系统API,包含<winsock.h>就能调用windows系统下的API。 
(2)手机端(客户端)socket 
手机端socket 调用import java.net.Socket和ServerSocket包中的socket类 。创建客户端套接字。 
实现代码可以参考(本人还未实现~) 
http://blog.csdn.net/yanjiaye520/article/details/7567309

6.手机与手机的通信

7.手机与智能家居的通信

8.web网站中前端和后端通信

9.ajax异步通信方式原理


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值