socket套接字(服务器和客户端编程)linux网络编程

it2023-01-13  58

概述

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口

编程流程

服务器端: 1.socket() 建立套接字 2.bind() 绑定IP端口号 (struct sockaddr_in addr 初始化) 3.listen() 指定同时最大连接数 4.accept() 阻塞等待客服端发起连接 5.read() 读取数据 6.处理数据,大小写转换 7.write() 回写给客户端 8.循环读写 9.close

客户端: 1.socket() 建立套接字 2.bind() 绑定IP端口号 (struct sockaddr_in addr 初始化)(隐式绑定默认调用,客户端可以不写这个函数) 3.connect() 发起连接 4.write() 写数据 5.read() 读取数据 6.循环读写 7.close

struct sockaddr_in addr结构如下

服务器

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<ctype.h> #include<arpa/inet.h> #include<string.h> #define SERV_IP "127.0.0.1" #define SERV_PORT 6666 //端口号 int main() { int lfd,cfd; struct sockaddr_in serv_addr;//传入参数,设置属性 struct sockaddr_in clien_addr;//传出参数,获取客户端属性 socklen_t clien_addr_len,clien_ip_len; //传出参数 char buf_ip[BUFSIZ];//缓冲区 int n,ret; lfd=socket(AF_INET,SOCK_STREAM,0);//建立本地套接字 /*参数1:选择网络IP类型 * AF_INET: IPV4标准; * AF_INET6: IPV6标准 * 参数2:选择协议种类 * SOCK_STREAM:基于字节流的连接,默认TCP连接 * SOCK_DGRAM: 无连接、固定长度的传输调用,默认UDP连接 * 参数3:选择默认方式,一般为0,表示参数2使用默认协议。 */ if(lfd==-1) { perror("socket error "); exit(1); } int opt=1; setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); //端口地址复用,当服务器主动关闭时,就算处于wait_time状态(主动关闭一方最后需要等待2MSL时间确保最后一个ACK发送成功,保证完整的4次握手关闭连接),重启后也能马上连接新的客户端 bzero(&serv_addr,sizeof(serv_addr)); //初始化 serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(SERV_PORT); //绑定端口,本地字节序转换为网络字节序,兼容各个平台大小端的模式。 //serv_addr.sin_addr.s_addr=inet_pton(SERV_IP);//本地IP转化为网络字节序 serv_addr.sin_addr.s_addr=htons(INADDR_ANY);//INADDR_ANY宏自动寻找一个可用的IP ret=bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定端口和IP /*参数1:套接字描述符 *参数2:属性设置的结构体,注意要强转(版本遗留问题,原先结构体已废弃) *参数3:结构体大小 */ if(ret==-1) { perror("bind error"); exit(1); } ret=listen(lfd,128);//允许最大128个客服端同时连接,同时使lfd成为一个监听描述符 if(ret==-1) { perror("listen error"); exit(1); } clien_addr_len=sizeof(clien_addr); //设置默认大小 cfd=accept(lfd,(struct sockaddr *)&clien_addr,&clien_addr_len); /*参数1:套接字描述符 *参数2:传出参数,表示客户端属性 *参数3:传入传出参数 *返回一个新的socket文件描述符,用于与客户端通信 */ if(cfd==-1) { perror("accept error"); exit(1); } printf("client IP: %s,client port:%d\n ", inet_ntop(AF_INET,&clien_addr.sin_addr.s_addr,buf_ip,sizeof(buf_ip)), ntohs(clien_addr.sin_port)); while(1) { char buf[BUFSIZ]; memset(buf,0,sizeof(buf)); // printf("buf size=%lu ,strlen=%d ",sizeof(buf),strlen(buf)); n=read(cfd,buf,sizeof(buf));//读取 if(n==0) break; printf("accept buf %s, length=%d\n",buf,n); for(int i=0;i<n;i++)//字符串全部转为大写 buf[i]=toupper(buf[i]); write(cfd,buf,n);//写入 } close(lfd); close(cfd); return 0; }

客户端

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<ctype.h> #include<arpa/inet.h> #include<string.h> #define SERV_IP "127.0.0.1" #define SERV_PORT 6666 int main() { int cfd,sfd; struct sockaddr_in serv_addr; socklen_t serv_addr_len; char buf[BUFSIZ],clien_ip[BUFSIZ]; int n; char *find; memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(SERV_PORT);//转换为网络字节序 //serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY可以自行寻找ip inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr); cfd=socket(AF_INET,SOCK_STREAM,0);//创建本地套接字 // bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定 connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr) ); while(1) { fgets(buf,sizeof(buf),stdin);//从输入端读一行数据存入缓存区中 find=strchr(buf,'\n'); if(find) *find='\0';//去掉fgets中的换行符 write(cfd,buf,strlen(buf)); n=read(cfd,buf,sizeof(buf)); write(STDOUT_FILENO,buf,n); printf("\n"); } close(cfd); return 0; }

结果如下:成功实现通信和返回处理

最新回复(0)