话不多说先看代码:
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等函数的出错处理,有了出错处理函数,上述情况的发生是可以大大减小的。