操作系统里的进程通讯方式有6种:(有名/匿名)管道、信号、消息队列、信号量、内存(最快)、套接字(最常用),这里我们来介绍用socket来实现进程通讯。

 

1、简单实现一个单向发送与接收

这是套接字的工作流程

(对于有时间想慢慢看的推荐这篇博客:https://www.cnblogs.com/kefeiGame/p/7246942.html)

C++ socket 网络编程 简单聊天室

 (不想自己画一遍,直接用别人的)

 

我们现在先来实现套接字对同一主机的通讯。(代码注释比较全

服务器(虚拟机[Ubuntu]):

  1 #include <unistd.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <arpa/inet.h>
  5 #include <sys/socket.h>
  6 
  7 #define MYPORT 1223///开应一个端口
  8 #define IP "**.**.**.**"///你用的服务器的IPv4地址,这里我用了虚拟机(ubuntu)的地址
  9 #define BACKLOG 10
 10 #define getLen(zero) sizeof(zero) / sizeof(zero[0]) ///得到数组最大大小
 11 using namespace std;
 12 
 13 int main() {
 14     int sockfd, new_fd;
 15     struct sockaddr_in my_addr;
 16     puts("SERVER:");
 17     if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
 18         ///socket()函数发生错误则返回-1,否则会返回套接字文件描述符
 19         ///对于int socket(int domain, int type, int protocol);中的参数想要详细了解可以看这篇博客:https://blog.csdn.net/liuxingen/article/details/44995467
 20 
 21         perror("socket():");///显示错误
 22         return 0;
 23     }
 24     my_addr.sin_family = AF_INET;///通讯在IPv4网络通信范围内
 25     my_addr.sin_port = htons(MYPORT);///我的端口
 26     my_addr.sin_addr.s_addr = inet_addr(IP);///用来得到一个32位的IPv4地址,inet_addr将"127.0.0.1"转换成s_addr的无符号整型。
 27     bzero(&(my_addr.sin_zero), getLen(my_addr.sin_zero));///sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
 28 
 29     /**
 30         借用以下代码得到了my_addr.sin_addr.s_addr的类型是无符号整型
 31         unsigned int a;
 32         if(typeid(a) == typeid(my_addr.sin_addr.s_addr)){
 33             puts("Yes");
 34         }
 35     **/
 36 
 37 
 38     if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {///bind()函数将套接字与该IP:端口绑定起来。
 39         perror("bind():");
 40         return 0;
 41     }
 42     if(listen(sockfd, BACKLOG) == -1) {///启动监听,等待接入请求,BACKLOG是在进入队列中允许的连接数目
 43         perror("listen():");
 44         return 0;
 45     }
 46 
 47     socklen_t sin_size;
 48     struct sockaddr_in their_addr;
 49     if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
 50         ///当你监听到一个来自客户端的connect请求时,要选择是将他放在请求队列里还是允许其连接,我这里写的其实是单进客户的,所以说无等待。
 51         ///这个函数还返回了一个新的套接字,用于与该进程通讯。
 52         ///还有一点是之前推荐的c++中的socket编程(入门),该博客里写的sin_size类型是int,可是实际上我在linux的C++环境下出现错误,类型要是socklen_t。
 53         perror("accept():");
 54         return 0;
 55     }
 56     printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));///inet_ntoa可以将inet_addr函数得到的无符号整型转为字符串IP
 57 
 58     char str[1007];
 59 
 60     while(1) {///循环发送 以endS结束与这一进程的通讯,endS也作为客户端停止工作的标志送出
 61         puts("send:");
 62         scanf("%s", str);
 63         if(send(new_fd, str, strlen(str), 0) == -1) {
 64             ///send()函数,new_fd是accept返回的套接字文件描述符,str就你要发送的数据,数据长度,对于最后一位flag
 65             /// flags取值有:
 66             /// 0: 与write()无异(我自己也不知道什么意思,大概就是常规操作,以下提供几种flag值的定义,然后下面是这类宏定义的源码)
 67 
 68 ///            MSG_DONTROUTE 绕过路由表查找。
 69 ///            MSG_DONTWAIT 仅本操作非阻塞。
 70 ///            MSG_OOB 发送或接收带外数据。
 71 ///            MSG_PEEK 窥看外来消息。
 72 ///            MSG_WAITALL 等待所有数据。
 73 ///
 74 ///            源码里没找到0x00的定义,所以说我将其当作默认参数
 75 ///            enum
 76 ///              {
 77 ///                MSG_OOB             = 0x01, /// Process out-of-band data.
 78 ///            #define MSG_OOB         MSG_OOB
 79 ///                MSG_PEEK            = 0x02, /// Peek at incoming messages.
 80 ///            #define MSG_PEEK        MSG_PEEK
 81 ///                MSG_DONTROUTE       = 0x04, /// Don't use local routing.
 82 ///            #define MSG_DONTROUTE   MSG_DONTROUTE
 83 ///            #ifdef __USE_GNU
 84 ///                /// DECnet uses a different name.
 85 ///                MSG_TRYHARD         = MSG_DONTROUTE,
 86 ///            # define MSG_TRYHARD    MSG_DONTROUTE
 87 ///            #endif
 88 ///                MSG_CTRUNC          = 0x08, /// Control data lost before delivery.
 89 ///            #define MSG_CTRUNC      MSG_CTRUNC
 90 ///                MSG_PROXY           = 0x10,  /// Supply or ask second address.
 91 ///            #define MSG_PROXY       MSG_PROXY
 92 ///                MSG_TRUNC           = 0x20,
 93 ///            #define MSG_TRUNC       MSG_TRUNC
 94 ///                MSG_DONTWAIT        = 0x40,  /// Nonblocking IO.
 95 ///            #define MSG_DONTWAIT    MSG_DONTWAIT
 96 ///                MSG_EOR             = 0x80,  /// End of record.
 97 ///            #define MSG_EOR         MSG_EOR
 98 ///                MSG_WAITALL         = 0x100,  /// Wait for a full request.
 99 ///            #define MSG_WAITALL     MSG_WAITALL
100 ///                MSG_FIN             = 0x200,
101 ///            #define MSG_FIN         MSG_FIN
102 ///                MSG_SYN             = 0x400,
103 ///            #define MSG_SYN         MSG_SYN
104 ///                MSG_CONFIRM         = 0x800,  /// Confirm path validity.
105 ///            #define MSG_CONFIRM     MSG_CONFIRM
106 ///                MSG_RST             = 0x1000,
107 ///            #define MSG_RST         MSG_RST
108 ///                MSG_ERRQUEUE        = 0x2000,  /// Fetch message from error queue.
109 ///            #define MSG_ERRQUEUE    MSG_ERRQUEUE
110 ///                MSG_NOSIGNAL        = 0x4000,  /// Do not generate SIGPIPE.
111 ///            #define MSG_NOSIGNAL    MSG_NOSIGNAL
112 ///                MSG_MORE            = 0x8000,   /// Sender will send more.
113 ///            #define MSG_MORE        MSG_MORE
114 ///                MSG_WAITFORONE      = 0x10000,  /// Wait for at least one packet to return.
115 ///            #define MSG_WAITFORONE  MSG_WAITFORONE
116 ///                MSG_BATCH           = 0x40000,  /// sendmmsg: more messages coming.
117 ///            #define MSG_BATCH       MSG_BATCH
118 ///                MSG_ZEROCOPY        = 0x4000000, /// Use user data in kernel path.
119 ///            #define MSG_ZEROCOPY    MSG_ZEROCOPY
120 ///                MSG_FASTOPEN        = 0x20000000, /// Send data in TCP SYN.
121 ///            #define MSG_FASTOPEN    MSG_FASTOPEN
122 ///
123 ///                MSG_CMSG_CLOEXEC    = 0x40000000    /// Set close_on_exit for file
124 ///                                                       ///descriptor received through
125 ///                                                       ///SCM_RIGHTS.
126 ///            #define MSG_CMSG_CLOEXEC MSG_CMSG_CLOEXEC
127 ///              };
128 
129             perror("send():");
130             close(new_fd);///发送失败就关闭该通讯
131             return 0;
132         }
133         if(!strcmp("endS", str))
134             break;
135     }
136     close(new_fd);///正常结束要关闭这些已建立的套接字
137     close(sockfd);
138 
139     return 0;
140 }
linux环境的服务端

相关文章:

  • 2021-04-03
  • 2021-07-25
  • 2021-04-20
  • 2021-12-10
  • 2021-08-05
  • 2021-07-05
  • 2022-02-01
猜你喜欢
  • 2022-01-12
  • 2021-07-14
  • 2022-12-23
  • 2022-12-23
  • 2021-10-26
  • 2021-09-17
  • 2021-08-19
相关资源
相似解决方案