本文共 6693 字,大约阅读时间需要 22 分钟。
客户端的调用序列: 调用socket函数创建套接字 调用connect连接服务器端 调用I/O函数(read/write)函数与服务器端进行通讯 调用close关闭套接字服务器端调用序列 调用socket函数创建套接字 调用bind绑定本地地址和端口 调用listen启动监听 调用accept从已连接队列中提取客户连接 调用(I/O)函数(read/write)与客户端进行通讯 调用close关闭套接字
绑定地址
#includeint 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
查找绑定到套接字的地址
#includeint getsockname(int sockfd,struct sockaddr * restrict addr,socklen_t * restrict alenp); 返回:成功返回0,失败返回-1
获取对方地址
#includeint getpeername(int sockfd,struct sockaddr *restrict addr,socklen_t * restrict alenp); 返回:成功返回0,失败返回-1
服务器端
#includeint listen(int sockfd,int backlog);返回:成功返回0,失败返回-1,backlog指定进行客户端连接排队的队列长度int accept(int sockfd,struct sockaddr * restrict addr,socklen_t *restrict len);addr :客户端连接上来的时候的地址信息sockfd:传过来的sock的文件描述符
客户端
#includeint connect(int sockfd,const struct sockaddr * addr,socklen_t len);返回:成功返回0,失败返回-1
/* * =========================================================================== * * 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#include #include #include #include #include #include #include #include #include #include //注意自定义的头文件需要放在系统的头文件之后#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#include #include #include #include #include #include #include #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#include #include #include #include #include #include #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上显得稍微复杂了点,但是原理上其实都是一样的
转载地址:http://tzbsn.baihongyu.com/