socket通信的几个关键步骤
2013-03-14 10:49
411 查看
转自点击打开链接
面向连接的socket通信就像与对方打电话,首先需要通过电话建立一个连接,连接建立好之后,彼此才能双向通信。它有几个关键步骤
服务器端通常以守护进程的方式实现:
1: 创建守护进程
2:获取或注册服务
3:创建socket并绑定地址
4:开始监听
5:接收客户端连接请求
6:进行数据传输
客户端
1:获取或注册服务
2:创建socket
3:发送连接请求
示例代码
服务器端的实现(以端口的形式提供给用户使用)
测试流程:服务器端: 修改/etc/hosts如下
192.168.1.11 X64-server
127.0.0.1 localhost
#127.0.1.1 X64-server
客户端 修改/etc/hosts如下
127.0.0.1 localhost
127.0.1.1 ubuntu
192.168.1.11 X64-server
说明:若服务器端以服务的形式提供给用的使用,服务端和客户端都需要在/etc/services中注册服务,但它们的端口号可以不一样,如:ruptime 2001/tcp,然后将getaddrinfo函数中端口号改为服务名就可以了
面向无连接Socket通信
而向无连接的socket通信就向发电子邮件一样,数据通信之前不需要建立连接的。
面向连接的socket通信就像与对方打电话,首先需要通过电话建立一个连接,连接建立好之后,彼此才能双向通信。它有几个关键步骤
服务器端通常以守护进程的方式实现:
1: 创建守护进程
2:获取或注册服务
3:创建socket并绑定地址
4:开始监听
5:接收客户端连接请求
6:进行数据传输
客户端
1:获取或注册服务
2:创建socket
3:发送连接请求
示例代码
服务器端的实现(以端口的形式提供给用户使用)
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <arpa/inet.h> #include <stddef.h> /* for offsetof */ #include <string.h> /* for convenience */ #include <unistd.h> /* for convenience */ #include <signal.h> /* for SIG_ERR */ #include <errno.h> #include <syslog.h> #include <sys/socket.h> #include <fcntl.h> #include <sys/resource.h> #define BUFLEN 128 #define QLEN 10 #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 256 #endif void daemonize(const char *cmd) { int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa; /* * Clear file creation mask. */ umask(0); /* * Get maximum number of file descriptors. */ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) printf("%s: can't get file limit", cmd); /* * Become a session leader to lose controlling TTY. */ if ((pid = fork()) < 0) printf("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); setsid(); /* * Ensure future opens won't allocate controlling TTYs. */ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) printf("%s: can't ignore SIGHUP"); if ((pid = fork()) < 0) printf("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); /* * Change the current working directory to the root so * we won't prevent file systems from being unmounted. */ if (chdir("/") < 0) printf("%s: can't change directory to /"); /* * Close all open file descriptors. */ if (rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for (i = 0; i < rl.rlim_max; i++) close(i); /* * Attach file descriptors 0, 1, and 2 to /dev/null. */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); /* * Initialize the log file. */ openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2); exit(1); } } int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen) { int fd; int err = 0; if ((fd = socket(addr->sa_family, type, 0)) < 0) return(-1); if (bind(fd, addr, alen) < 0) { err = errno; goto errout; } if (type == SOCK_STREAM || type == SOCK_SEQPACKET) { if (listen(fd, qlen) < 0) { err = errno; goto errout; } } return(fd); errout: close(fd); errno = err; return(-1); } void serve(int sockfd) { int clfd; FILE *fp; char buf[BUFLEN]; for (;;) { clfd = accept(sockfd, NULL, NULL); if (clfd < 0) { syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno)); exit(1); } if ((fp = popen("/usr/bin/uptime", "r")) == NULL) { sprintf(buf, "error: %s\n", strerror(errno)); send(clfd, buf, strlen(buf), 0); } else { while (fgets(buf, BUFLEN, fp) != NULL) send(clfd, buf, strlen(buf), 0); pclose(fp); } close(clfd); } } int main(int argc, char *argv[]) { struct addrinfo *ailist, *aip; struct addrinfo hint; int sockfd, err, n; char *host; if (argc != 1) printf("usage: ruptimed"); #ifdef _SC_HOST_NAME_MAX n = sysconf(_SC_HOST_NAME_MAX); if (n < 0) /* best guess */ #endif n = HOST_NAME_MAX; host = malloc(n); if (host == NULL) printf("malloc error"); if (gethostname(host, n) < 0) printf("gethostname error"); printf("hostname=%s\n",host); daemonize("ruptimed"); hint.ai_flags = AI_PASSIVE; hint.ai_family = 0; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = 0; hint.ai_addrlen = 0; hint.ai_canonname = NULL; hint.ai_addr = NULL; hint.ai_next = NULL; if ((err = getaddrinfo(host, "2001", &hint, &ailist)) != 0) { syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s",gai_strerror(err)); exit(1); } for (aip = ailist; aip != NULL; aip = aip->ai_next) { if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr,aip->ai_addrlen, QLEN)) >= 0) { printf("initserver ok !\n"); serve(sockfd); exit(0); } } printf("server err !\n"); exit(1); } 客户端的实现 #include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <arpa/inet.h> #include <unistd.h> /* for convenience */ #include <sys/resource.h> #include <errno.h> #include <sys/socket.h> #define MAXADDRLEN 256 #define BUFLEN 128 #define MAXSLEEP 128 int connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen) { int nsec; /* * Try to connect with exponential backoff. */ for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) { if (connect(sockfd, addr, alen) == 0) { /* * Connection accepted. */ return(0); } /* * Delay before trying again. */ if (nsec <= MAXSLEEP/2) sleep(nsec); } return(-1); } void print_uptime(int sockfd) { int n; char buf[BUFLEN]; while ((n = recv(sockfd, buf, BUFLEN, 0)) > 0) write(STDOUT_FILENO, buf, n); if (n < 0) printf("recv error"); } int main(int argc, char *argv[]) { struct addrinfo *ailist, *aip; struct addrinfo hint; int sockfd, err; if (argc != 2) printf("usage: ruptime hostname"); hint.ai_flags = AI_CANONNAME; hint.ai_family = 0; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = 0; hint.ai_addrlen = 0; hint.ai_canonname = NULL; hint.ai_addr = NULL; hint.ai_next = NULL; if ((err = getaddrinfo(argv[1], "2001", &hint, &ailist)) != 0) printf("getaddrinfo error: %s", gai_strerror(err)); for (aip = ailist; aip != NULL; aip = aip->ai_next) { if ((sockfd = socket(aip->ai_family, SOCK_STREAM, 0)) < 0) err = errno; if (connect_retry(sockfd, aip->ai_addr, aip->ai_addrlen) < 0) { err = errno; } else { print_uptime(sockfd); exit(0); } } fprintf(stderr, "can't connect to %s: %s\n", argv[1],strerror(err)); exit(1); }
测试流程:服务器端: 修改/etc/hosts如下
192.168.1.11 X64-server
127.0.0.1 localhost
#127.0.1.1 X64-server
客户端 修改/etc/hosts如下
127.0.0.1 localhost
127.0.1.1 ubuntu
192.168.1.11 X64-server
说明:若服务器端以服务的形式提供给用的使用,服务端和客户端都需要在/etc/services中注册服务,但它们的端口号可以不一样,如:ruptime 2001/tcp,然后将getaddrinfo函数中端口号改为服务名就可以了
面向无连接Socket通信
而向无连接的socket通信就向发电子邮件一样,数据通信之前不需要建立连接的。
相关文章推荐
- ios socket通信的几个关键步骤
- socket通信的几个关键步骤
- 初遇SOCKET套接字(简单通信步骤)
- java网络通信基于UDP的几个步骤
- java Socket通信实现步骤
- 关于COPC后台配置的几个关键步骤及其事务代码
- esxi嵌套华为Fusioncomputer安装VRM几个关键步骤。
- Socket通信原理步骤
- Windows下socket通信步骤
- socket 通信 多线程调用窗体(委托)的几个知识点,记录在案,以备查阅
- socket通信中的几个函数--accept(),send(),recv()
- 简单socket通信步骤
- SOCKET通信的基本步骤
- 一次IPC通信过程的几个步骤
- 使用Socket连接穿越CMWAP代理与完整的HTTP通信步骤7步
- 详解——socket通信步骤
- SqlServer 调优的几个关键的步骤--sp_lock,sp_who
- 纯socket编程有几个步骤
- 销售工作业务员谈业务的几个关键步骤