Linux网络编程之[基于socket通信的tcp协议的编程模型]
2017-04-23 14:10
1286 查看
Linux网络编程之[基于socket通信的tcp协议的编程模型]
TCP客户端服务器的编程模型(傻瓜式通信流程)TCP协议的相关函数
3 基于TCP协议的案例
TCP客户端服务器的编程模型(傻瓜式通信流程)
客户端的调用序列: 调用socket函数创建套接字 调用connect连接服务器端 调用I/O函数(read/write)函数与服务器端进行通讯 调用close关闭套接字 服务器端调用序列 调用socket函数创建套接字 调用bind绑定本地地址和端口 调用listen启动监听 调用accept从已连接队列中提取客户连接 调用(I/O)函数(read/write)与客户端进行通讯 调用close关闭套接字
TCP协议的相关函数
绑定地址#include<sys/socket.h> int bind(int sockfd,const struct sockaddr * addr,socklen_t len); 返回:成功返回0,出错返回-1 一台主机往往有多个网络接口和多个IP地址, 如果我们只去关心某个地址的连接请求, 我们可以指定一个具体的本地IP地址,如果要想用所有接口上的连接请求,就要使用一个特殊的INADDR_ANY #define INADDR_ANY (uint32_t)0x00000000 //监听所有服务器上ip得到的连接请求 struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_addr.s_addr = INADDR_ANY
查找绑定到套接字的地址
#include<sys/socket.h> int getsockname(int sockfd,struct sockaddr * restrict addr,socklen_t * restrict alenp); 返回:成功返回0,失败返回-1
获取对方地址
#include<sys/socket.h> int getpeername(int sockfd,struct sockaddr *restrict addr,socklen_t * restrict alenp); 返回:成功返回0,失败返回-1
服务器端
#include<sys/socket.h> int listen(int sockfd,int backlog); 返回:成功返回0,失败返回-1,backlog指定进行客户端连接排队的队列长度 int accept(int sockfd,struct sockaddr * restrict addr,socklen_t *restrict len); addr :客户端连接上来的时候的地址信息 sockfd:传过来的sock的文件描述符
客户端
#include<sys/socket.h> int connect(int sockfd,const struct sockaddr * addr,socklen_t len); 返回:成功返回0,失败返回-1
基于TCP协议的案例
/* * =========================================================================== * * Filename: socket_utils.h * Description: * Version: 1.0 * Created: 2017年04月23日 11时26分40秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */ #ifndef __SOCKET_UTILS_H_ #define __SOCKET_UTILS_H_ extern void readSocketAddr(struct sockaddr_in *addr); extern void readSocket(int socketfd); extern void writeSocket(int socketfd); #endif
/* * =========================================================================== * * Filename: socket_utils.c * Description: * Version: 1.0 * Created: 2017年04月23日 11时28分45秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */ #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/socket.h> #include<sys/types.h> #include<netdb.h> #include<memory.h> #include<sys/types.h> #include<arpa/inet.h> #include<time.h> //注意自定义的头文件需要放在系统的头文件之后 #include"socket_utils.h" /* * *读取连接过来的客户端地址的信息 * */ extern void readSocketAddr(struct sockaddr_in *addr){ //将网络字节序转换成本地字节序 int port = ntohs(addr->sin_port); char ip[16]; memset(ip,0,sizeof(ip)); //将ip地址从网络字节序转换成点分十进制形式 inet_ntop(AF_INET,&addr->sin_addr.s_addr,ip,sizeof(ip)); printf("client:%s(%d) connected\n",ip,port); } /* * *向对应的socket描述符中去读取数据 * */ extern void readSocket(int socketfd){ char buffer[1024]; memset(buffer,0,1024); ssize_t size; if((size= read(socketfd,buffer,sizeof(buffer))) < 0){ perror("read error\n"); exit(1); } if(write(STDOUT_FILENO,buffer,size) != size){ perror("write error"); exit(1); } } /* * *向对应的socket描述符中去写数据 * */ void writeSocket(int socketfd){ time_t t = time(0); char *s = ctime(&t); size_t size = strlen(s) * sizeof(char); //char result[] = "server connected success\n"; //连接成功后会先给客户端返回一个时间 if(write(socketfd,s,size) != size){ perror("write error\n"); exit(1); } }
/* * =========================================================================== * * Filename: server.c * Description: TCP的server端的开发 * Version: 1.0 * Created: 2017年04月22日 22时46分58秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */ #include<netdb.h> #include<unistd.h> #include<string.h> #include<stdio.h> #include<stdlib.h> #include<memory.h> #include<signal.h> #include<time.h> #include"socket_utils.h" //创建socket的描述符号 int sockfd; void sig_handler(int sig){ if(sig ==SIGINT){ printf("server close\n"); close(sockfd); exit(1); } } int main(int argc,char *argv[]){ //从参数中传入端口号 if(argc < 2){ printf("参数不齐"); exit(1); } if(signal(SIGINT,sig_handler) == SIG_ERR){ perror("signal sigint error"); exit(1); } /* * *步骤一:创建socket,TCP协议是sock_strem(创建在内核中的) * */ sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd < 0){ perror("socket create error\n"); exit(0); } /* * *配置socket的参数,绑定ip和端口 * */ struct sockaddr_in addr_in; memset(&addr_in,0,sizeof(addr_in)); addr_in.sin_family = AF_INET;//IP_V4 addr_in.sin_port = htons(atoi(argv[1]));//将本地字节序号转化成网络字节序号 addr_in.sin_addr.s_addr = INADDR_ANY;//服务器端监听所有服务器上ip得到的连接请求,转换成同时也是需要将其转换成网络字节序 if(bind(sockfd,(struct sockaddr*)&addr_in,sizeof(addr_in)) < 0){ perror("bind error\n"); exit(1); } /* * *启动对listen监听,通知系统去接受来自客户端的连接请求操作 *将接受到的客户端连接请求放置到对应的队列中去 * */ if(listen(sockfd,100) < 0){ perror("listen error\n"); exit(1); } /** * 使用while死循环来让server端一直等待客户端的连接,并且从连接队列中提取客户连接 */ struct sockaddr_in clientaddr; memset(&clientaddr,0,sizeof(clientaddr)); socklen_t len = sizeof(clientaddr); while(1){ //拿到客户端的sock描述符好,读写操作 int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len); if(clientfd < 0){ perror("recieve clientfd error"); continue; } readSocketAddr(&clientaddr); readSocket(clientfd); writeSocket(clientfd); } return 0; }
/* * =========================================================================== * * Filename: tcp_client.c * Description: * Version: 1.0 * Created: 2017年04月23日 12时49分30秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<memory.h> #include<netdb.h> #include"socket_utils.h" int main(int argc,char * argv[]){ if(argc < 3){ perror("缺少参数"); exit(1); } /* * *创建socket * */ int clientsockfd = socket(AF_INET,SOCK_STREAM,0); if(clientsockfd < 0){ perror("socket error"); exit(1); } /* * *往serveraddr中填入ip,port和地址族类型(ipv4)connect的过程 * */ struct sockaddr_in socketaddr; memset(&socketaddr,0,sizeof(socketaddr)); socketaddr.sin_family = AF_INET; socketaddr.sin_port = htons((short)atoi(argv[2])); if(inet_pton(AF_INET,argv[1],&socketaddr.sin_addr.s_addr) <= 0){ perror("pton change error\n"); exit(1); } if(connect(clientsockfd,(struct sockaddr*)&socketaddr,sizeof(socketaddr)) < 0){ perror("connect error"); exit(1); } /* * *调用IO函数(read/write)和服务器端进行双向通信 * */ //readSocket(clientsockfd); close(clientsockfd); return 0; }
以上的代码都是可以直接进行run的,这只是一个单连接的小demo,如果server端支持多端连接的并且分别通信的话,需要加入线程等操作.在这里就没有展示了,相对于java中的socket调用,在C上显得稍微复杂了点,但是原理上其实都是一样的
欢迎持续访问博客
相关文章推荐
- socket编程 -- 基于TCP协议的C/S通信模型及实现
- uc笔记10---网络通信,套接字(Socket),基于 TCP 协议的客户机/服务器模型
- Linux Socket 网络编程 基于GTK+ 的多线程实现的局域网通信软件
- 线程与网络编程(第六节:通信协议与TCP socket初识)
- socket 网络编程快速入门(一)教你编写基于UDP/TCP的服务(客户端)通信
- socket 网络编程高速入门(一)教你编写基于UDP/TCP的服务(client)通信
- linux网络编程之socket(十四):基于UDP协议的网络程序
- linux网络编程之socket(十四):基于UDP协议的网络程序
- linux网络编程之用socket实现简单客户端和服务端的通信(基于UDP)
- Socket编程——基于TCP实现自己的通信协议
- linux下第一个socket编程实现的局域网内通信(基于TCP)
- linux网络编程之socket(十四):基于UDP协议的网络程序
- Linux Socket 网络编程 基于GTK+ 的多线程实现的局域网通信软件
- 网络编程(5)—— 基于Linux系统的UDP协议socket服务器和客户端
- socket编程 -- 基于UDP协议的C/S通信模型及实现
- socket 网络编程快速入门(二)教你编写基于UDP/TCP的服务端多线程通信
- Linux网络编程之socket简单通信TCP--服务端代码
- Linux网络编程【六】:TCP协议高性能服务器(http)模型之I/O多路转接epoll
- 网络层、传输层、应用层、端口通信协议编程接口 - http,socket,tcp/ip 网络传输与通讯知识总结
- 基于tcp_socket通信的网络编程