假设有两个进程(RoseGarden和WeatherForecast)之间需要通信,其中前者作为服务器,后者作为客户端。
这里的socket使用最常见的domain(AF_INET,即IPV4),使用的通讯类型为SOCK_STREAM。
服务器端代码如下:
#include <iostream>
#include <unistd.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <signal.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <vector>
using namespace std;
int main() {
cout << "*****************************" << endl;
cout << "******* RoseGarden ********" << endl;
cout << "*****************************" << endl;
string hostname = "localhost.localdomain";
string servname = "hello";
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
int err;
struct addrinfo *ailist, *aip;
if ((err = getaddrinfo(hostname.data(), servname.data(), &hint, &ailist)) != 0) {
cerr << "<RoseGarden> Error: " << gai_strerror(err) << endl;
exit(1);
}
vector<int> sockfd;
int fd;
for (aip = ailist; aip != NULL; aip = aip->ai_next) {
if ((fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) < 0)
continue;
if (bind(fd, aip->ai_addr, aip->ai_addrlen) < 0) {
close(fd);
continue;
}
if (listen(fd, 1) < 0) {
close(fd);
continue;
}
sockfd.push_back(fd);
cout << "<RoseGarden> valid SOCKFD = " << fd << endl;
}
int clfd;
clfd = accept(sockfd[0], NULL, NULL);
cout << "<RoseGarden> valid CLIENT SOCKFD = " << clfd << endl;
int count;
string sbuf;
while (1) {
sbuf = "<RoseGarden> " + to_string(count++) + " message.";
send(clfd, sbuf.data(), sbuf.size(), 0);
sleep(1);
}
return 0;
}
客户端代码如下:
#include <iostream>
#include <unistd.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <signal.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
cout << "*****************************" << endl;
cout << "***** WeatherForecast *****" << endl;
cout << "*****************************" << endl;
if (argv[1] == NULL) {
cerr << "Error: Please input address and service-name." << endl;
exit(1);
}
if (argv[2] == NULL) {
cerr << "Error: Please input service-name." << endl;
exit(1);
}
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
int err;
struct addrinfo *ailist, *aip;
if ((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0) {
cerr << "<WeatherForcast> Error: " << gai_strerror(err) << endl;
exit(1);
}
vector<int> sockfd;
int fd;
for (aip = ailist; aip != NULL; aip = aip->ai_next) {
if ((fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) < 0)
continue;
if (connect(fd, aip->ai_addr, aip->ai_addrlen) != 0) {
close(fd);
continue;
}
sockfd.push_back(fd);
cout << "<WeatherForcast> valid SOCKFD = " << fd << endl;
}
char rbuf[128];
int n;
while (1) {
memset(rbuf, 0, sizeof(rbuf));
n = recv(sockfd[0], rbuf, sizeof(rbuf), 0);
if (n > 0)
cout << "<WeatherForcase> R: " << rbuf << endl;
}
return 0;
}
客户端执行结果:
$ ./RoseGarden
*****************************
******* RoseGarden ********
*****************************
<RoseGarden> valid SOCKFD = 3
<RoseGarden> valid CLIENT SOCKFD = 4
服务器端执行结果:
$ ./WeatherForecast 127.0.0.1 hello
*****************************
***** WeatherForecast *****
*****************************
<WeatherForcast> valid SOCKFD = 3
<WeatherForcase> R: <RoseGarden> 0 message.
<WeatherForcase> R: <RoseGarden> 1 message.
<WeatherForcase> R: <RoseGarden> 2 message.
<WeatherForcase> R: <RoseGarden> 3 message.
<WeatherForcase> R: <RoseGarden> 4 message.
<WeatherForcase> R: <RoseGarden> 5 message.
虽然socket的原理很复杂,它使用起来却很简单。
《Unix环境高级编程》这本书的第16章讲的就是socket的用法。
刚开始看的时候,可能会被很多数量的结构体和函数绕晕了,但是没关系,看第二遍的时候就会清晰很多。
ps:多实验代码,将结构体的值打印出来观察~
文章评论(0条评论)
登录后参与讨论