该篇博客为自己学习服务器编程的记录,如有理解上的偏差,欢迎评论区指正。
一、细节问题
1.关于read函数返回值:
1.正常情况下会返回 buffer 中读取到的数据大小;
2.当客户端提前调用close(socket_fd)时会返回0,表示客户端断开连接;
3.当客户端未调用close函数直接退出程序,服务器read返回-1,read 函数执行出错。
2.在服务器端创建 server_address的时候,设置服务器IP,端口:
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//"127.0.0.1" 不区分多个服务IP。
若设置为服务器ip时,会导致监听端口随机变化,客户端无法连接。因此建议使用INADDR_ANY。该字段应该是为了区分多IP服务器的参数。
3.perror使用
1 #include "util.h" 2 #include <stdlib.h> 3 #include <iostream> 4 5 void errif(bool condition,const char *errmsg){ 6 if(condition){ 7 perror(errmsg); 8 exit(EXIT_FAILURE);//宏定义为1, 0表示正常退出 9 } 10 }
当服务器未开启时,连接错误,后半段错误信息是perror额外输出(通过读取系统错误状态)
4.运行时代码中的ip更换为自己服务器的ip,或者本地测试更换为127.0.0.1
二、代码:
1.服务器端
1 #include <iostream> 2 #include <stdio.h> 3 #include <arpa/inet.h> 4 #include <sys/socket.h> 5 #include <cstring> 6 #include <unistd.h> 7 #include "util.h" 8 #include <string> 9 using namespace std; 10 11 int main(int argc,char **argv){ 12 13 int sockfd=socket(AF_INET,SOCK_STREAM,0); 14 errif(sockfd==-1,"socket create error"); 15 struct sockaddr_in serv_addr; 16 bzero(&serv_addr,sizeof(serv_addr)); 17 serv_addr.sin_family=AF_INET; 18 //serv_addr.sin_addr.s_addr=inet_addr("1.14.93.142");//127.0.0.1 // INADDR_ANY //使用固定ip会导致监听端口为随机。 19 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//127.0.0.1 // "1.14.93.142",不区分多个服务IP。 20 serv_addr.sin_port=htons(8880);//8880 21 printf("server fd: %d! IP:%s Port:%d\n",sockfd,inet_ntoa(serv_addr.sin_addr),ntohs(serv_addr.sin_port)); 22 errif(bind(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr))==-1,"serv_addr bind error !"); 23 errif(listen(sockfd,SOMAXCONN)==-1,"socket listen error");//系统默认一个线程最大有128个acceped等待队列,即三次握手完成后,等待服务器线程处理的等待队列。 24 25 struct sockaddr_in clnt_addr; 26 socklen_t clnt_addr_len=sizeof(clnt_addr); 27 bzero(&clnt_addr,sizeof(clnt_addr)); 28 int clnt_sockfd =accept(sockfd,(sockaddr*)&clnt_addr,&clnt_addr_len); 29 errif(clnt_sockfd==-1,"socket accept error !"); 30 printf("new client fd: %d! IP:%s Port:%d\n",clnt_sockfd,inet_ntoa(clnt_addr.sin_addr),ntohs(clnt_addr.sin_port)); 31 string welcom="Welcome to krito's server \n"; 32 write(clnt_sockfd,welcom.c_str(),sizeof(welcom)); 33 while(true){ 34 char buf[1024]; 35 memset(buf,0,sizeof(buf)); 36 ssize_t read_bytes=read(clnt_sockfd,buf,sizeof(buf)); 37 if(read_bytes>0){ 38 printf("message from client fd %d: %s \n",clnt_sockfd,buf); 39 write(clnt_sockfd,buf,sizeof(buf)); 40 }else if(read_bytes==0){ 41 printf("client fd %d disconnected \n",clnt_sockfd); 42 close(clnt_sockfd); 43 break; 44 }else{ 45 close (clnt_sockfd); 46 errif(true,"socket read error"); 47 } 48 } 49 close(sockfd); 50 cout<<"server exit !"<<endl; 51 return 0; 52 } 53 54 /*、 55 g++ -o server server.cpp util.cpp 56 */
2.客户端:
1 #include <iostream> 2 #include<arpa/inet.h> 3 #include <sys/socket.h> 4 #include <string.h> 5 #include <stdio.h> 6 #include <unistd.h> 7 #include "util.h" 8 //using namespace std; 9 10 int main(){ 11 int sockfd=socket(AF_INET,SOCK_STREAM,0); 12 errif(sockfd==-1,"socket create error"); 13 struct sockaddr_in serv_addr; 14 bzero(&serv_addr,sizeof(serv_addr)); 15 serv_addr.sin_family=AF_INET; 16 serv_addr.sin_addr.s_addr=inet_addr("1.14.93.142");//127.0.0.1 17 serv_addr.sin_port=htons(8880); 18 printf("set server fd: %d! IP:%s Port:%d\n",sockfd,inet_ntoa(serv_addr.sin_addr),ntohs(serv_addr.sin_port)); 19 errif(connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)),"socket connect error !"); 20 while(true){ 21 char buf[1024]; 22 memset(buf,0,sizeof(buf)); 23 scanf("%s",buf); 24 ssize_t write_bytes = write(sockfd,buf,sizeof(buf)); 25 if(write_bytes==-1){ 26 printf("socket already disconnected,can't write any more!\n"); 27 break; 28 } 29 memset(buf,0,sizeof(buf)); 30 ssize_t read_bytes=read(sockfd,buf,sizeof(buf)); 31 if(read_bytes>0){ 32 printf("message from server: %s\n",buf); 33 }else if(read_bytes==0){ 34 printf("server socket has disconnected\n"); 35 break; 36 }else{ 37 close(sockfd); 38 errif(true,"socket read error");//read出错,提前退出程序,返回错误代码。 39 } 40 } 41 std::cout<<"client exit"<<std::endl; 42 return 0; 43 }
3.其它函数:
util.cpp
1 #include "util.h" 2 #include <stdlib.h> 3 #include <iostream> 4 5 void errif(bool condition,const char *errmsg){ 6 if(condition){ 7 perror(errmsg); 8 exit(EXIT_FAILURE);//宏定义为1, 0表示正常退出 9 } 10 }
util.h
1 #ifndef UTIL_H 2 3 #define UTIL_H 4 void errif(bool ,const char*); 5 6 #endif
三、运行结果:
先运行服务端后,再打开客户端,输入: "krito: sit here !"
3.1服务端
编译:
g++ -o server server.cpp util.cpp

3.2客户端
编译:
g++ -o client client.cpp util.cpp


浙公网安备 33010602011771号