Linux网络编程之[基于socket通信的tcp协议的编程模型]

来源:互联网 发布:淘宝怎么能分期付款 编辑:程序博客网 时间:2024/05/19 12:39

Linux网络编程之[基于socket通信的tcp协议的编程模型]

  1. TCP客户端服务器的编程模型(傻瓜式通信流程)
  2. 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上显得稍微复杂了点,但是原理上其实都是一样的

欢迎持续访问博客

1 0
原创粉丝点击