关于TCP套接字编程中的send()引起的断开的通道

在用多线程编写可以支持多个客户端连接的远程控制系统时,当非正常关闭客户端时服务器老出现断开的通道;

原来的代码,

#include<stdlib.h>
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#define PORT 8900
#define SIZE 2048

FILE *mypopen(char *command,char type)
{
	int pipefd[2];
	pid_t pid;
	char *argv[10];
	int i;

	if(pipe(pipefd)<0)
	{
		printf("create mypopen fail");
		return NULL;
	}

	pid = fork();

	if(pid==0)
	{
		if(type=='r')
		{
			close(pipefd[0]);
			dup2(pipefd[1],STDOUT_FILENO);
			close(pipefd[1]);
		}
		execl("/bin/sh","sh","-c",command,(char *) 0);
		_exit(0);

	}
	else if(pid>0)
	{
		wait(0);
		if(type=='r')
		{
			close(pipefd[1]);
			return fdopen(pipefd[0],"r");
		}
	}
		
}

void 	exec (char* command,char* result)
{
	
	FILE * in;
	int len;
	char c;
	
	len=0;
	
	bzero(result,sizeof(result));
	in=mypopen(command,'r');

	if (NULL==in)
	{
		fprintf(stderr,"error in create a pipe\n");
	}
	
	while(((c=fgetc(in))!=EOF)&&(len<SIZE))
	{
		result[len]=c;
		len++;
	}
	
	result[len]='\0';
	
	if (0==len)
	{
		sprintf(result,"%s cannot execute\n",command);
	}
}
void serverItem(void *a)		
{
	
	int connectd = (int)a;
	char send_buf[2048];
	char recv_buf[2048];
	char cmd[2048];
	int recvnum;
	int rvalue;
	char path[2048];

	bzero(cmd,10);
	bzero(path,2048);

	while(1)
	{
		memset(send_buf,0,2048);
		memset(recv_buf,0,2048);
		recvnum = recv(connectd,recv_buf,sizeof(recv_buf),0);

		if (0>recvnum)
		{
			perror("recv error\n");
			continue;
		}
	
		recv_buf[recvnum]='\0';

		sscanf(recv_buf,"%s %s",cmd,path);
		if ((0==strcmp("cd",cmd)) ||(0==strcmp("CD",cmd)))
		{
			chdir(path);
 			printf("%s",path);
			continue;
		}
		if (0==strcmp("quit\n",recv_buf))
		{
			continue;
		}
		else
		{
			exec(recv_buf,send_buf);
		}
	
		rvalue=-1;
		rvalue=send(connectd,send_buf,strlen(send_buf),0);
		if (0>rvalue)
		{
			fprintf(stderr,"error in sending data\n");
			continue;
		}
	}
}
int main(int argc,char** argv)
{
	struct sockaddr_in server;
	struct sockaddr_in client;
	int len;
	int port;
	int listend;
	int connectd;
	int sendnum;
	int opt;
	int sockfd;
	pthread_t thread;
      //if (2==argc)

	sockfd=-1;
	bzero(&client,sizeof(struct sockaddr));
	bzero(&server,sizeof(struct sockaddr));
	len=-1;
	port=PORT;
	opt=SO_REUSEADDR;
      

	if (-1==(listend=socket(AF_INET,SOCK_STREAM,0)))
	{
		perror("create listen socket error\n");
		exit(1);
      	}
	setsockopt(listend,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

	#ifdef DEBUG
	printf("the listen id is %d\n",listend);
	#endif

	memset(&server,0,sizeof(struct sockaddr_in));
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = htonl(INADDR_ANY);
	server.sin_port = htons(port);

	if (-1==bind(listend,(struct sockaddr *)&server,sizeof(struct sockaddr)))
	{
		perror("bind error\n");
		exit(1);
	}

	if (-1==listen(listend,5))
	{
		perror("listen error\n");
		exit(1);
	}
	len = sizeof(struct sockaddr);

	while (1)
	{
		if (-1==(connectd=accept(listend,(struct sockaddr*)&client,&len)))
		{
			perror("create connect socket error\n");
			continue;
		}
		pthread_create(&thread,NULL,(void*)serverItem,(void *)connectd);
	}
    close(listend);
    return 0;

}

运行结果,当非正常关闭客户端时,服务器会出现断开的通道,



首先,自己上网搜了一下Socked send函数的用法,

要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)

注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

上面一段文字来自:http://www.cnblogs.com/cgun/archive/2010/05/25/1743636.html

也正是这个原因才出现了上面所说的断开的通道的错误。

我调试程序发现当我们关闭客户端的窗口时,服务器仍会接收到一连串的东西,当服务器端接收到来自客户端的命令时(当然这不是真正有意义的命令),服务器就会响应客户端,通过send函数把buf中的数据copy到server的发送缓冲区它就返回了。由于此时c/s连接已经断开,这些数据并没有被发送出去。接着服务器接收下一个指令,并继续调用send函数去响应客户端,由于上次东西没被发送出去,所以就出现了SOCKET_ERROR,并终止了当前进程,从而出现了断开的通道。

解决方法很简单:其实也是本人了解太少了,,如果连接断开recv()函数会返回一个0,我们对其进行处理就行了。

else if(0==recvnum)
	break;
貌似和send没关,但这个错误却促使我去认真了解了send函数



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值