当前位置: 首页>編程日記>正文

linux网络编程--socket服务器和客户端TCP编程及多进程编程

linux网络编程--socket服务器和客户端TCP编程及多进程编程

文章目录

  • 1.网络编程中客户端与服务器通信基本流程
  • 2. 服务器和客户端编程实现<迭代服务器>
    • 2.1. 迭代服务器编程实现
      • 2.1.1. 命令行参数解析
      • 2.1.2. 创建服务器 socket
      • 2.1.3. bind 绑定端口和ip 并且 开启listen
      • 2.1.4. 开启accept
      • 2.1.5. 通过文件IO系统调用对客户端进行读写
    • 2.2. 客户端编程实现
      • 2.2.1 客户端命令行参数解析(带域名解析功能)
      • 2.2.2. 创建客户端socket
      • 2.2.3. 与服务器进行连接connect
      • 2.2.4. 通过文件IO系统调用对服务器进行读写
  • 3. 服务器+多进程编程
    • 3.1. 简单介绍多进程编程
    • 3.2 编程实现

1.网络编程中客户端与服务器通信基本流程

网络socket通讯基本流程

2. 服务器和客户端编程实现<迭代服务器>

2.1. 迭代服务器编程实现

2.1.1. 命令行参数解析

  1. 服务器参数只有端口号,增加一个帮助参数<-h>,对该命令的用法进行说明
  2. 代码编写如下
void print_usage(char *progname)
{printf("%s usage: \n", progname);printf("-p(--port): sepcify server port.\n");printf("-h(--Help): print this help information.\n");return ;
}
{int                  port = 0;int                  ch;struct option        opts[] = {{"port", required_argument, NULL, 'p'},{"help", no_argument, NULL, 'h'},{NULL, 0, NULL, 0}};while( (ch=getopt_long(argc, argv, "p:h", opts, NULL)) != -1 ) {switch(ch){case 'p':port=atoi(optarg);//字符串 ----> 整形break;case 'h':print_usage(argv[0]);return 0;}}if(!port) //未正常使用命令{print_usage(argv[0]);return 0;}
}

2.1.2. 创建服务器 socket

{socket_fd = socket(AF_INET, SOCK_STREAM, 0);//IPV4   TCPif(socket_fd < 0){printf("Create socket failure : %s\n", strerror(errno));return -1;}printf("Create socket [%d] successful!\n", socket_fd);    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//防止程序端口重用报错
}

2.1.3. bind 绑定端口和ip 并且 开启listen

{memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(port);       // 主机字节序 ----> 网络字节序servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有的 IP 主机-----> 网络rv = bind(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));if(rv < 0){printf("Socket[%d] bind on port [%d] failure : %s\n",socket_fd,port,strerror(errno));return -2;}printf("Socket[%d] bind on port [%d] successful!\n", socket_fd, port);//listen listen(socket_fd, 13);
}

2.1.4. 开启accept

  1. accept是一个阻塞函数,当 没有客户端连接服务器的时候,该程序会一直阻塞不返回,直到有一个客户端连接过来为止。当客户端调用connect函数就会触发服务器的accept函数返回,此时TCP连接就建立好了。
  2. 代码实现
//acceptclifd = accept(socket_fd, (struct sockaddr *)&cliaddr, &len);if(clifd < 0){printf("Accept new client failure:%s\n", strerror(errno));continue;}printf("Accept new client [%s:%d] successfully!\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));//客户端的IP和端口

2.1.5. 通过文件IO系统调用对客户端进行读写

  1. 读客户端编程实现,使用read系统调用
{memset(buf, 0, sizeof(buf));rv = read(clifd, buf, sizeof(buf));if(rv < 0){printf("Read from client by clifd[%d] failure: %s\n", clifd , strerror(errno));close(clifd);continue;     }else if(rv == 0){printf("Clifd[%d] get disconnected\n", clifd);close(clifd);continue;}else if(rv > 0){printf("Read [%d] byte data from client clifd[%d] : %s\n", rv, clifd, buf);}
}
  1. 对客户端进行write写消息,注意写完后不想继续通讯,需要关闭客户端描述符。
{rv = write(clifd, MSG_STR, strlen(MSG_STR));if(rv < 0)    {             printf("write to client by clifd[%d] failure: %s\n", clifd , strerror(errno));close(clifd);continue;}  printf("Close client fd[%d]\n", clifd);close(clifd);
}
  1. 服务器关闭前也需要把监听前创建的socket描述符关闭。

2.2. 客户端编程实现

2.2.1 客户端命令行参数解析(带域名解析功能)

  1. 客户端参数有 服务器ip地址和服务器端口,增加帮助命令<-h>,增加域名命令<-d>,该代码仅实现域名的解析并打印其ip地址,由于没有公网IP无法进行测试,测试baidu.com可以解析出其IP地址
{int                  ch;struct option        opts[] = {{"ipaddr", required_argument, NULL, 'i'},{"port", required_argument, NULL, 'p'},{"domain_name", required_argument, NULL, 'd'},{"help", no_argument, NULL, 'h'},{NULL, 0, NULL, 0}};while( (ch=getopt_long(argc, argv, "i:p:d:h", opts, NULL)) != -1 ) {switch(ch){case 'i':servip=optarg;break;case 'p':port=atoi(optarg);break;case 'd':ser_domain_name=optarg;break;case 'h':print_usage(argv[0]);return 0;}}if( !servip || !port || !ser_domain_name){print_usage(argv[0]);return 0;}//打印域名和解析后的IP地址p = gethostbyname(ser_domain_name);printf("domain_name : %s servip : %s\n", ser_domain_name, inet_ntoa(*((struct in_addr *)p->h_addr)));
}

2.2.2. 创建客户端socket

  1. 使用IPV4和TCP通讯
{socket_fd = socket(AF_INET, SOCK_STREAM, 0);if(socket_fd < 0){printf("Create socket failure :%s\n", strerror(errno));return -1;}printf("Create socket [%d] successful!\n", socket_fd);
}

2.2.3. 与服务器进行连接connect

  1. 把参数通过规定进行传入,注意字节序和字符串转换
{memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port   = htons(port);// 主----> 网inet_aton(servip, &servaddr.sin_addr);    //字符串  -----> 网络字节序rv = connect(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));if(rv < 0){printf("Connect to server [%s:%d] failure : %s\n", servip, port, strerror(errno));return -2;}printf("Connect to server [%s:%d] successful!\n", servip, port);
}

2.2.4. 通过文件IO系统调用对服务器进行读写

  1. 和服务器一样,使用read和write进行消息的读写
  2. 注意客户端与服务器结束通讯后,不想继续通讯便可关闭socket描述符
{rv = write(socket_fd, MSG_STR, strlen(MSG_STR));if(rv < 0){printf("Write to server by socket_fd [%d] failure : %s\n", socket_fd, strerror(errno));break;}//readmemset(buf, 0, sizeof(buf));rv = read(socket_fd, buf, sizeof(buf));if(rv < 0){printf("Read from server by sockfd[%d] failure: %s\n", socket_fd , strerror(errno));break;    }else if(0 == rv){printf("Socketfd[%d] get disconnected\n", socket_fd);break;}else if(rv > 0){printf("Read [%d] byte from server socket_fd [%d] : %s\n", rv, socket_fd, buf);}close(socket_fd);
}

3. 服务器+多进程编程

3.1. 简单介绍多进程编程

  1. 迭代服务器一次只能与一个客户端进行通讯,而实际中会有大量和客户端与服务器进行访问通讯,此时迭代服务器便不再适用。
  2. 使用多进程编程实现并发服务器,结构框图如下
    多进程编程实现并发服务器

3.2 编程实现

  1. 多进程编程实现,在原有的服务器代码上进行修改,在接收到客户端连接请求后,开启子进程与客户端进行通讯
{pid = fork();if(pid < 0){printf("fork() create child process failure : %s\n", strerror(errno));close(cli_fd);}else if(pid > 0) // 父进程 的功能函数{close(cli_fd); //父进程 不需要 客户端描述符continue;}else if(0 == pid){close(socket_fd); //子进程不需要 该fd,该fd用于监听,监听到了后,使用新的fd....//服务器与客户端通讯部分}
}


https://www.fengoutiyan.com/post/15827.html

相关文章:

  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機