socket多进程TCP通信
来源:互联网 发布:小工具源码 编辑:程序博客网 时间:2024/06/07 07:47
才能的火花,常常在勤奋的磨石上迸发。 —— 威廉·李卜克内西
上一篇写了一些socket基本的本地通信,本篇文章说一下我们的socket网络通信。而网络通信分为TCP协议和UDP协议,这篇文章给出的是TCP协议。
TCP是传输层的协议,又为传输控制协议,在TCP通信中,我们需要必须的通信材料:端口和IP地址。
IP地址是网络中的唯一标识,通过IP地址即可找到我们的计算机,因为IP地址本质为一个整数,绑定我们网卡的MAC地址,即物理地址,物理地址是唯一的。IP又分为IPv4和IPv6,前者为32位整数,后者为128位整数,我们的IP地址一般用点分十进制表示,便于记忆,即8位16进制数表示,因此在编程的时候应该要转换。而为了更便于记忆,又推出了助记符,即域名/网址的概念,域名经过域名解析服务器完成IP的转换。
由于IP地址只能定位计算机,而不能定位在计算机中运行的程序,即进程,所以我们用端口对外管理进程,端口本质是一个非负的short型整数,(0~65535),因为short为两个字节,所以我们的端口号也是两个字节来表示,一般有些端口被固定的服务器所占用,所以我们选用端口号的时候尽量选择大的,大于4096位普通用户可以使用。
常用端口号:
当然,端口号我们可以自己进行修改和定义,但是这样做无疑是作死。
而由于我们的计算机存储数据的方式不同,有的是大端,有的是小端,网络的存储格式为大端的,即高地址对应高数据位,小端则相反,因此我们统一将IP转换为网络大端字节序。
和PIC本地通信一样,网络通信也是非常的套路,但是其中很多细节的设置以及技巧用法耐人寻味,这里介绍的是多进程的编程,多进程编程耗费CPU资源较大,但是限于笔者能力,只能先结合网络的力量写一个多进程的socket编程
先介绍要用到的结构体以及相关函数:
#include <netinet/in.h>struct sockaddr_in{ int sin_family; //用于指定协议族,和socket一致 short sin_port; //端口号 struct sin_addr s_addr; //存储IP地址的结构}
这些用作参数时同样要转换为sockaddr类型。
socket(int domain, int type, int protocol);bind(int sockfd, struct sockaddr* addr, socklen_t size);connect(int sockfd, struct sockaddr* addr, socklen_t size);listen(sockfd, len);accept(int fd, struct sockaddr* addr, socklen_t* len);
socket、bind、connect函数在前面已经介绍过,这里不做重复
listen函数用于与多个客户端同时请求时,放入等待队列中,第二个参数为等待队列最大长度
accept函数是比较重要的函数,第一个参数为socket的返回值,addr为一个传入传出参数,传入addr的真实长度,传出接收到的客户端的通信地址的真实长度,当然,这两个值一般都相同。返回成功,返回值为一个新的socket描述符,以后即可对这个新的描述符进行读写操作,失败则返回-1。
接下来说一下编程的步骤吧:
服务器
1、socket
2、准备我们的通信地址结构体
3、服务器端为bind
4、监听listen
5、等待客户端连接,函数accept,返回新的描述符用于读写交互,accept相当于阻塞函数
6、读写函数
7、关闭socket
客户端与前面的一样,只是多了准备通信地址结构体。
下面给出本人结合其他信息的socket多进程程序:
服务器端:
/********************************************************************************* * Copyright: (C) 2017 tangyanjun<519656780@qq.com> * All rights reserved. * * Filename: myserver.c * Description: This file * * Version: 1.0.0(06/06/2017) * Author: tangyanjun <519656780@qq.com> * ChangeLog: 1, Release initial version on "06/06/2017 06:57:03 PM" * ********************************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <time.h>#include <arpa/inet.h>#include <signal.h>int fd;void fa(int signo) //用一个信号正常关闭文件描述符{ printf("服务器即将关闭!\n"); sleep(2); close(fd); exit(0);}/* void TIME() { time_t timep; time(&timep); printf("当前时间:%s", ctime(&timep));}*/void TIME() //一个现实当前时间的函数{ char buf[100] = {}; time_t cur_time = time(0); struct tm* cur = localtime(&cur_time); 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); printf("当前时间:%s\n", buf);}int main(int argc, char **argv){ TIME(); printf("请按ctrl+C退出服务器\n"); signal(SIGINT, fa); //发送信号关闭文件描述符 fd = socket(AF_INET, SOCK_STREAM, 0); //socket if (fd == -1) perror("socket"), exit(-1); struct sockaddr_in addr; //定义一系列结构体 addr.sin_family = AF_INET; addr.sin_port = htons(2222); addr.sin_addr.s_addr = inet_addr("10.154.216.80"); int reuse = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); //避免地址冲突 int res = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); //绑定 if (res == -1) perror("bind"), exit(-1); printf("bind ok!\n"); listen(fd, 100); //监听 while(1){ struct sockaddr_in from; socklen_t len = sizeof(from); int newfd = accept(fd, (struct sockaddr*)&from, &len); //有客户连接,则返回新的描述符 if (newfd == -1) perror("accept"), exit(-1); printf("%s连接了\n", inet_ntoa(from.sin_addr)); TIME(); pid_t pid = fork(); //有客户来时,创建一个子进程来处理 if(!pid) { char buf[100] = {}; while(1){ res = read(newfd, buf, sizeof(buf)); //对新的描述符进行读写操作 TIME(); printf("读到了%d个字节,内容是%s\n", res, buf); if (res == -1) perror("read"), exit(-1); else if(!res) break; if (!strcmp(buf, "byebye")) //当客户输入相应字符时,可知客户端退出了 { printf("%s退出了\n", inet_ntoa(from.sin_addr)); break; } write(newfd, buf, strlen(buf)); memset(buf, 0, strlen(buf)); //清空buf } close(newfd); //子进程关闭新的描述符 exit(0); } close(newfd); //父进程关闭新的描述符 } // close(fd); return 0;}
客户端:
/********************************************************************************* * Copyright: (C) 2017 tangyanjun<519656780@qq.com> * All rights reserved. * * Filename: myclient.c * Description: This file * * Version: 1.0.0(06/06/2017) * Author: tangyanjun <519656780@qq.com> * ChangeLog: 1, Release initial version on "06/06/2017 07:12:06 PM" * ********************************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <time.h>#include <arpa/inet.h>#include <time.h>/* void TIME(){ time_t timep; time(&timep); printf("当前时间:%s", ctime(&timep));}*/void TIME() //时间函数{ char buf[100] = {}; time_t cur_time = time(0); struct tm* cur = localtime(&cur_time); 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); printf("当前时间:%s\n", buf);}int main(int argc, char **argv){ int fd = socket(AF_INET, SOCK_STREAM, 0); //socket if (fd == -1) perror("socket"), exit(-1); struct sockaddr_in addr; //定义结构体相关内容 addr.sin_family = AF_INET; addr.sin_port = htons(2222); addr.sin_addr.s_addr = inet_addr("10.154.216.80"); int res = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); //连接服务器端 if (res == -1) perror("connect"), exit(-1); printf("connect ok!\n"); char buf[100] = {}; char buf1[100] = {}; while(1){ TIME(); printf("请输入聊天内容:\n"); scanf("%s", buf); write(fd, buf, strlen(buf)); if (!strcmp(buf, "byebye")) break; //输入相应字符退出 int res = read(fd, buf1, strlen(buf1)); if (res == -1) { perror("read"); break; } printf("read:%s\n", buf1); memset(buf, 0, strlen(buf)); memset(buf1, 0, strlen(buf1)); } close(fd); return 0;}
运行结果:
这就是一个简单的一对多的多进程通,后续文章将会写多线程通信,以及多路复用。
- socket多进程TCP通信
- tcp通信:多进程共享listen socket方式
- TCP通信,多进程
- 使用 异步多线程TCP Socket 实现进程间通信
- 【原创】TCP Socket 简单练习 --- 新进程辅助通信
- socket编程(TCP单进程客户服务器通信)
- 进程通信之 Socket (顺便回顾 TCP UDP)
- tcp ip 通信socket
- socket网络通信(tcp)
- socket TCP通信实例
- socket网络通信(tcp)
- <>socket-通信-tcp协议
- Linux Socket TCP通信
- TCP Socket通信学习
- tcp ip 通信socket
- linux TCP socket 通信
- C++ TCP socket通信
- linux Tcp 通信socket
- Ambari安装trafodion
- MTK驱动移植相关路径
- Tomcat端口占用问题
- java中反射操作私有成员变量
- iOS App上架流程
- socket多进程TCP通信
- 项目总结-管理收尾
- Object.keys方法
- 论java的重要性
- 我的第一个Android程序
- POJ 1149 网络流最大流 解题报告
- App实战节选-购物车
- 读《JAVA 编程及其应用》【英文版】
- 摄像机