socket编程遇到难以理解的问题

HW_Coder0501 2016-10-07 07:34:26
下面是一个聊天室的程序,可以实现多个客户端发消息然后在服务器端显示的功能(每个客户端都会显示本用户输入的消息)。
/*server.c (服务器端程序)*/
nclude <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

//#define 1000 //在一条消息中最大的输出字符数
#define LISTENQ 20 //最大监听队列
#define PORT 5000 //监听端口
#define MAXFD 20 //最大的在线用户数量
void *get_client(void *);
int sockfd,i;
static int maxi=0;//maxi表示当前client数组中最大的用户的i值
static int client[MAXFD];

void recvandsend(void) //监听转发线程入口函数
{
int index=0;
int nbytes=0;
char buffer[1024];
//int len;
int outindex=0;
while(1)
{
if(maxi>0)
{
memset(buffer,0,sizeof(buffer));
nbytes=0;
//index++;
nbytes=read(client[index++],buffer,sizeof(buffer)); //read(int fd, const void *buf, size_t length); client[] -> buf
// printf("%d,%d\n",index,client[index]);
if(nbytes>0)
{
buffer[nbytes]='\0';
printf("%s\n",buffer); //经验证,buffer为服务器端输出内容如张三:你好
outindex=0;
/*屏蔽以下5行,客户端没有输出如张三:你好的信息,可推知此几句将buffer中的内容返回到新sockfd中(不知理解是否有误?)*/
while(outindex<maxi)
if(write(client[outindex++],buffer,sizeof(buffer))==-1) // buffer -> client[] {
{ fprintf(stderr,"WriteError:%s\n",strerror(errno));
exit(1);
}

}
}
if(index>=maxi)
index=0;
}
pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
// intclient_fd[LISTENQ],clientnum=0;;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size,portnumber;
char hello[]="Hello! Are You Fine?\n";
int thr_id; /* thread ID for the newly createdthread */
pthread_t p_thread; /* thread's structure */
int new_fd=0;
memset(client,0,sizeof(client)); //static int client[MAXFD];
if(argc!=1)
{
fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);
exit(1);
}

/* 服务器端开始建立 socket 描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));
exit(1);
}
/* 服务器端填充 sockaddr 结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
/* 捆绑 sockfd 描述符 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Binderror:%s\n\a",strerror(errno));
exit(1);
}
printf("服务器监听端口%d...\n",PORT);
/* 监听 sockfd 描述符 */
if(listen(sockfd,LISTENQ)==-1)
{
fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));
exit(1);
}
thr_id =pthread_create(&p_thread, NULL, recvandsend, NULL);
printf("欢迎来到本聊天室\n");
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
if(maxi>=20)
{
printf("以达到人数上线\n");
continue;
}
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
{
fprintf(stderr,"Accepterror:%s\n\a",strerror(errno));
exit(1);
}
/*fprintf(stderr,"Serverget connection from %s\n",inet_ntoa(client_addr.sin_addr));*/
client[maxi++]=new_fd; //new_fd 是新sockfd
printf("\n新用户进入聊天室%d\n",new_fd);
}
close(sockfd);
exit(0);
}



/* client.c (客户端程序) */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define TRUE 1
#define PORT 5000

static int sockfd;
void recvfromserver() //接受服务器消息线程入口函数
{
char mes[1024];
int nbytes=0;

while(1)
{
memset(mes,0,sizeof(mes));
nbytes=read(sockfd,mes,sizeof(mes)); //成功则返回读取字节数
if(nbytes>0)
{
mes[nbytes]='\0';
printf("%s\n",mes
}
}
pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber,nbytes;
char strhost[16];
char clientname[20];
char mes[1024];
int thr_id; /* thread ID for the newly createdthread */
pthread_t p_thread; /* thread's structure */
if(argc!=1)
{
fprintf(stderr,"Usage:%s\a\n",argv[0]);
exit(1);
}
printf("请输入服务器ip地址\n");
scanf("%s",strhost); //strhost为要输入的IP地址
if((host=gethostbyname(strhost))==NULL)
{
fprintf(stderr,"Gethostnameerror\n");
exit(1);
}
/* 客户程序开始建立 sockfd 描述符 */
printf("正在建立套接口...\n");
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"SocketError:%s\a\n",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr=*((struct in_addr *)host->h_addr);//IP地址
printf("套接口创建成功,正在链接服务器...\n");
/* 客户程序发起连接请求 */

if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));
exit(1);
}
/* 连接成功了 */
printf("链接服务器成功\n欢迎来到聊天室\n");
printf("请输入你的用户昵称\n");
scanf("%s",clientname); //此处应是输入了自己随意设置的名字如张三

printf("\n\n开始聊天吧(\"Quit\"断开连接)\n\n");


thr_id =pthread_create(&p_thread, NULL, recvfromserver, NULL);//recvfromserver为线程要执行函数
while(1) //先执行while后执行线程
{
memset(buffer,0,sizeof(buffer));
memset(mes,0,sizeof(mes));
scanf("%s",buffer);
strcat(mes,clientname); //将两个char类型连接,将clientname(张三)添加到mes后
strcat(mes,":");
strcat(mes,buffer);
if((write(sockfd,mes,sizeof(mes)))==-1) //将张三:你好写到socket,线程函数再将此信息读到mes输出
{
fprintf(stderr,"WriteError:%s\n",strerror(errno));
exit(1);
}
if(strcmp(buffer,"Quit")==0) //strcmp比较字符串
{
break;
}
}
/* 结束通讯 */
close(sockfd);
exit(0);
}

以上程序完整运行结果:客户端:
请输入服务器ip地址
127.0.0.1 //我输入
正在建立套接口...
套接字创建成功,正在连接服务器...
连接服务器成功
请输入昵称
张三 //我输入

开始聊天吧("Quit"断开连接)
你好 //我输入
张三:你好 //终端输出

.....................................分割线.............................................................................

服务器端:
欢迎来到本聊天室

新用户进入聊天室 4
张三:你好

图中红色部分,是服务器线程函数的一部分,按照我的理解这几行程序是buffer中的内容返回到connect返回的套接字中,然后由此套接字传到客户端程序,在客户端输出相应内容。 我将此几行程序去掉以后,按照原先的操作重新操作了一遍,服务器端可以正常输出“张三:你好”的信息,客户端没有输出,似乎和我的理解是一样的。
但当我将这几行恢复,并将 while(outindex<maxi) 改成while(1)之后,客户端输出正常,但服务器端却不断打印出“张三:你好”的信息,这个到底是怎么回事?应该怎样理解这几行程序?
...全文
358 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
HW_Coder0501 2016-10-09
  • 打赏
  • 举报
回复
引用 5 楼 codingMozart 的回复:
[quote=引用 4 楼 hhhlizhao 的回复:] [quote=引用 3 楼 codingMozart 的回复:] [quote=引用 2 楼 hhhlizhao 的回复:] [quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对[/quote] 还有一点疑问,在将while(outindex<max) 改成while(1)之后应该是while(1)之后的语句if(write(client[outindex++],buffer,sizeof(buffer))==-1)不断被执行,所以应该是客户端不断打印消息,但为什么我运行时却是服务器端不断打印消息?[/quote] client[outindex++] 是给每个客户发送回复,outindex在不断加,client[1],client[2]...是给客户端,直到max之后的描述符就不对应于一个客户了,max之后client[outindex++] 的描述符都是0,都是对应于服务端的控制台[/quote]
引用 5 楼 codingMozart 的回复:
[quote=引用 4 楼 hhhlizhao 的回复:] [quote=引用 3 楼 codingMozart 的回复:] [quote=引用 2 楼 hhhlizhao 的回复:] [quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对[/quote] 还有一点疑问,在将while(outindex<max) 改成while(1)之后应该是while(1)之后的语句if(write(client[outindex++],buffer,sizeof(buffer))==-1)不断被执行,所以应该是客户端不断打印消息,但为什么我运行时却是服务器端不断打印消息?[/quote] client[outindex++] 是给每个客户发送回复,outindex在不断加,client[1],client[2]...是给客户端,直到max之后的描述符就不对应于一个客户了,max之后client[outindex++] 的描述符都是0,都是对应于服务端的控制台[/quote] 好像只有第一个clien【】是真正的套接字,其他的都不是,服务器端连续打印20次就退出,可以参考下面那位兄台讲的。
codingMozart 2016-10-08
  • 打赏
  • 举报
回复
引用 2 楼 hhhlizhao 的回复:
[quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对
HW_Coder0501 2016-10-08
  • 打赏
  • 举报
回复
引用 1 楼 codingMozart 的回复:
while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?
apple_v1 2016-10-08
  • 打赏
  • 举报
回复
引用 4 楼 hhhlizhao 的回复:
[quote=引用 3 楼 codingMozart 的回复:] [quote=引用 2 楼 hhhlizhao 的回复:] [quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对[/quote] 还有一点疑问,在将while(outindex<max) 改成while(1)之后应该是while(1)之后的语句if(write(client[outindex++],buffer,sizeof(buffer))==-1)不断被执行,所以应该是客户端不断打印消息,但为什么我运行时却是服务器端不断打印消息?[/quote] 我说一下,client数组开始都是0,因为你有一个客户端连接,所以只有client[0]是套接字,1-19是0,20及以后是未知数。第一次write是写入你的客户端,往后是写入0描述符,也就是我们熟知的标准输入,直到写client[20]即一个不存在的套接字,应用程序会收到一个错误并终止。但是程序终止的时候却没有打印我们的错误信息语句,这好像有点奇怪。按道理说write应该返回-1然后打印错误信息并调用exit退出。但问题是执行write时已经是致命错误了(进程会收到一个SIGPIPE信号,我也不知道为什么会是这个信号),导致write来不及返回进程便终止了,自然也就不会打印错误信息了。还有一个问题,客户端会显示是正常的,但是服务器为什么也会打印呢?我们的线程是一直执行while的write函数写入标准输入,并没有打印缓冲区。答案是我们的程序非正常终止了,此时内核缓冲区有我们的刚写入的未读数据,这时内核会为我们把这部分数据打印出来。你看一下内核刚好打印了20次,就是我们write的20次。所以尽管我们没有打印语句,终端还是输出了。
codingMozart 2016-10-08
  • 打赏
  • 举报
回复
while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
codingMozart 2016-10-08
  • 打赏
  • 举报
回复
引用 4 楼 hhhlizhao 的回复:
[quote=引用 3 楼 codingMozart 的回复:] [quote=引用 2 楼 hhhlizhao 的回复:] [quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对[/quote] 还有一点疑问,在将while(outindex<max) 改成while(1)之后应该是while(1)之后的语句if(write(client[outindex++],buffer,sizeof(buffer))==-1)不断被执行,所以应该是客户端不断打印消息,但为什么我运行时却是服务器端不断打印消息?[/quote] client[outindex++] 是给每个客户发送回复,outindex在不断加,client[1],client[2]...是给客户端,直到max之后的描述符就不对应于一个客户了,max之后client[outindex++] 的描述符都是0,都是对应于服务端的控制台
HW_Coder0501 2016-10-08
  • 打赏
  • 举报
回复
引用 3 楼 codingMozart 的回复:
[quote=引用 2 楼 hhhlizhao 的回复:] [quote=引用 1 楼 codingMozart 的回复:] while(outindex<max) ,限定了outindex的范围,而while(1)之后,你的outindex是不断增加的,在正常发送给max范围内的描述符之后,会遇到client[outindex]为0的情况,即把buffer的内容输出到了0号描述符,也就是你的控制台,也有可能只写了若干行“张三:你好”的信息后,就报非法内存访问了,就是outindex大于了MAXFD
多谢前辈指点。那红色部分的代码到底应该怎么理解?它是返回给客户端的信息吗?[/quote]对[/quote] 还有一点疑问,在将while(outindex<max) 改成while(1)之后应该是while(1)之后的语句if(write(client[outindex++],buffer,sizeof(buffer))==-1)不断被执行,所以应该是客户端不断打印消息,但为什么我运行时却是服务器端不断打印消息?

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧