socket编程之回声服务器函数的陷阱

简介: 由connect函数使用不当导致的小错误 话不多说先看代码:

由connect函数使用不当导致的小错误

  话不多说先看代码:


server.c


#include<stdio.h>
#include<ctype.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#define SERVER_PORT 9527
int main(void) {
  int fd, cfd, n;
  struct sockaddr_in server_addr, client_addr;
  socklen_t len_c;
  char clie_IP[BUFSIZ];
  char buf[1024];
  bzero(&server_addr, 0);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(SERVER_PORT);
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  fd = socket(AF_INET, SOCK_STREAM, 0);
  bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  listen(fd, 25);
  len_c = sizeof(client_addr);
  cfd = accept(fd, (struct sockaddr*)&client_addr, &len_c);
  while (1) {
    n = read(cfd, buf, sizeof(buf));
    for (int i = 0; i < n; i++) {
      buf[i] = toupper(buf[i]);
    }
    write(cfd, buf, n);
    write(STDOUT_FILENO, buf, n);
  }
  close(cfd);
  return 0;
}
client.c
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<ctype.h>
#define SERVER_PORT 9527
#define SERVER_IP "127.0.0.1"
int main(void) {
  int sfd, n;
  struct sockaddr_in server_addr;
  char buf[1024];
  sfd = socket(AF_INET, SOCK_STREAM, 0);
  bzero(&server_addr, 0);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(SERVER_PORT);
  inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
  sfd =connect(sfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  while (1) { 
    fgets(buf, sizeof(buf), stdin);
    write(sfd, buf, strlen(buf));
    n = read(sfd, buf, sizeof(buf));
    write(STDOUT_FILENO, buf, n);
  }
  close(sfd);
  return 0;
}

最终效果:

client:可以看出来,并没有实现我们的小写转大写功能。

20210423112836511.png

server:

20210423114041387.png

服务器这端直接什么都没有?可以断定可定是出了什么问题了。那么我么继续去排查。


新server.c:主要用于排错


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#define SERV_PORT 9527
int main(void)
{
    int sfd, cfd;
    int len, i;
    char buf[BUFSIZ], clie_IP[BUFSIZ];
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    /*创建一个socket 指定IPv4协议族 TCP协议*/
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    /*初始化一个地址结构 man 7 ip 查看对应信息*/
    bzero(&serv_addr, sizeof(serv_addr));           //将整个结构体清零
    serv_addr.sin_family = AF_INET;                 //选择协议族为IPv4
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //监听本地所有IP地址
    serv_addr.sin_port = htons(SERV_PORT);          //绑定端口号    
    /*绑定服务器地址结构*/
    bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    /*设定链接上限,注意此处不阻塞*/
    listen(sfd, 64);                                //同一时刻允许向服务器发起链接请求的数量
    printf("wait for client connect ...\n");
    /*获取客户端地址结构大小*/ 
    clie_addr_len = sizeof(clie_addr_len);
    /*参数1是sfd; 参2传出参数, 参3传入传入参数, 全部是client端的参数*/
    cfd = accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);           /*监听客户端链接, 会阻塞*/
//打印出连接成功的客户端的ip和端口号
    printf("client IP:%s\tport:%d\n", 
            inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), 
            ntohs(clie_addr.sin_port));
    while (1) {
        /*读取客户端发送数据*/
        len = read(cfd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, len);
        /*处理客户端数据*/
        for (i = 0; i < len; i++)
            buf[i] = toupper(buf[i]);
        /*处理完数据回写给客户端*/
        write(cfd, buf, len); 
    }
    /*关闭链接*/
    close(sfd);
    close(cfd);
    return 0;
}

20210423112905251.png

服务器这端接受的客户端IP为0,也就是根本没有完成和客户端连接,所以客户端得到的是小写也就不足为奇了。


原因剖析:

请大家翻回去看看博主之前写的client.c的代码,write和read可定是没有任何问题的,那么还会有什么地方出问题呢?请仔细思考一下。


我们再来看看 connet函数吧:

截取部分:

20210423114558967.png完整博客:socket编程之 connect()函数

不知道大家是否发现了client.c的问题了?


博主一开始也是着了connect函数的道了,他调用成功之后的返回值居然是0而不是socket描述符。


所以我们可以知道为什么在新编写的server.c中会显示client的ip为0.0.0.0了吧。

20210423114921587.png

就是因为这行代码将本来已经与server连接好的sfd置零了。

删除之后在运行:

client:

20210423115101251.png

20210423115132302.png

所以由此我们需要知道,在做服务器开发的时候我们应该去封装一个专门针对于 bind listen accept connect等函数的出错处理,有了出错处理函数,上述情况的发生是可以大大减小的。


目录
相关文章
|
2月前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
176 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
2月前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
184 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
3月前
|
网络协议 数据处理 C语言
利用C语言基于poll实现TCP回声服务器的多路复用模型
此代码仅为示例,展示了如何基于 `poll`实现多路复用的TCP回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。
96 0
|
4月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
156 0
|
5月前
|
Java
如何在Java中实现多线程的Socket服务器?
在Java中,多线程Socket服务器能同时处理多个客户端连接以提升并发性能。示例代码展示了如何创建此类服务器:监听指定端口,并为每个新连接启动一个`ClientHandler`线程进行通信处理。使用线程池管理这些线程,提高了效率。`ClientHandler`读取客户端消息并响应,支持简单的文本交互,如发送欢迎信息及处理退出命令。
|
6月前
|
Java Android开发
Java Socket编程示例:服务器开启在8080端口监听,接收客户端连接并打印消息。
【6月更文挑战第23天】 Java Socket编程示例:服务器开启在8080端口监听,接收客户端连接并打印消息。客户端连接服务器,发送&quot;Hello, Server!&quot;后关闭。注意Android中需避免主线程进行网络操作。
118 4
|
5月前
|
Java 数据格式
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
105 0
|
2月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
31 0
|
5月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
62 4
|
5月前
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
【7月更文挑战第25天】在网络应用蓬勃发展的数字时代,Python凭借其简洁的语法和强大的库支持成为开发高效应用的首选。本文通过实时聊天室案例,介绍了Python Socket编程的基础与进阶技巧,包括服务器与客户端的建立、数据交换等基础篇内容,以及使用多线程和异步IO提升性能的进阶篇。基础示例展示了服务器端监听连接请求、接收转发消息,客户端连接服务器并收发消息的过程。进阶部分讨论了如何利用Python的`threading`模块和`asyncio`库来处理多客户端连接,提高应用的并发处理能力和响应速度。掌握这些技能,能使开发者在网络编程领域更加游刃有余,构建出高性能的应用程序。
38 3