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等函数的出错处理,有了出错处理函数,上述情况的发生是可以大大减小的。


目录
相关文章
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
233 2
|
11月前
|
网络协议 开发者 Python
Socket如何实现客户端和服务器间的通信
通过上述示例,展示了如何使用Python的Socket模块实现基本的客户端和服务器间的通信。Socket提供了一种简单且强大的方式来建立和管理网络连接,适用于各种网络编程应用。理解和掌握Socket编程,可以帮助开发者构建高效、稳定的网络应用程序。
597 10
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
827 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
780 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
195 0
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
268 2
|
消息中间件 网络协议 网络安全
Python Socket编程:打造你的专属网络通道,基础篇与进阶篇一网打尽!
【7月更文挑战第26天】在网络编程领域,Python以简洁语法和强大库支持成为构建应用的首选。Socket编程为核心,实现计算机间的数据交换。
276 1
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
938 0
|
安全 网络协议 网络安全
Python Socket编程大揭秘:从菜鸟到黑客的进阶之路,你准备好了吗?
【7月更文挑战第27天】Python Socket编程是网络开发的关键技能,它开启从简单数据传输到复杂应用的大门。Socket作为网络通信的基础,通过Python的`socket`模块可轻松实现跨网通信。
174 0

热门文章

最新文章