socket编程之回声服务器函数的陷阱
作者:互联网
由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:可以看出来,并没有实现我们的小写转大写功能。
server:
服务器这端直接什么都没有?可以断定可定是出了什么问题了。那么我么继续去排查。
新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;
}
服务器这端接受的客户端IP为0,也就是根本没有完成和客户端连接,所以客户端得到的是小写也就不足为奇了。
原因剖析:
请大家翻回去看看博主之前写的client.c的代码,write和read可定是没有任何问题的,那么还会有什么地方出问题呢?请仔细思考一下。
我们再来看看 connet函数吧:
截取部分:
完整博客:socket编程之 connect()函数
不知道大家是否发现了client.c的问题了?
博主一开始也是着了connect函数的道了,他调用成功之后的返回值居然是0而不是socket描述符。
所以我们可以知道为什么在新编写的server.c中会显示client的ip为0.0.0.0了吧。
就是因为这行代码将本来已经与server连接好的sfd置零了。
删除之后在运行:
client:
server:
所以由此我们需要知道,在做服务器开发的时候我们应该去封装一个专门针对于 bind listen accept connect等函数的出错处理,有了出错处理函数,上述情况的发生是可以大大减小的。
标签:socket,编程,len,server,服务器,sfd,include,buf,addr 来源: https://blog.csdn.net/dearQiHao/article/details/116048079