念两句诗

千古斜阳,无处问长安。
【宋代】张舜民《江神子·癸亥陈和叔会于赏心亭》

该篇博客为自己学习服务器编程的记录,如有理解上的偏差,欢迎评论区指正。

 

一、细节问题

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

 

 

 

 

 

posted on 2022-04-29 17:35  昔九  阅读(248)  评论(0)    收藏  举报