TCP Socket (Linux 系统下C语言实现)

 

(1)TCP Socket Server的通讯流程

1.blind the desired ip and port

	if(-1 == bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)))
	{
		perror("bind error/n");
		exit(0);
	}
	printf("bind seccessful/n");


2.监听指定端口

 

 

	if(-1 == listen(sockfd,BACKLOG))
	{
		perror("lisenning");
		exit(1);
	}
	printf("the server is listenning.../n");

3与client进行握手,建立socket连接

 

	if(-1 == (sockfd_client = accept(sockfd,(struct sockaddr*)&client_sockaddr,&sin_size)))
	{
		perror("accept");
		exit(1);
	}
	printf("accept connect./n");

4.监听socket数据

 

memset(buf,0,sizeof(buf));//先清空buf
if(-1 == (recvbytes = recv(sockfd_client,buf,MAXBUFSIZE,0)))
{
	perror("receive");
	exit(1);
}

(2)服务器接收阻塞的超时问题    参考:阻塞机制下的recv小结

 

 recv是socket编程中最常用的函数之一,在阻塞状态的recv有时候会返回不同的值,而对于错误值也有相应的错误码,分别对应不同的状态,下面是我针对常见的几种网络状态的简单总结。
      首先阻塞接收的recv有时候会返回0,这仅在socket被正常关闭时才会发生。
      而当拔掉设备网线的时候,recv并不会发生变化,仍然阻塞,如果在这个拔网线阶段,socket被关掉了,后果可能就是recv永久的阻塞了。
      所以一般对于阻塞的socket都会用setsockopt来设置socket的超时。
      当超时时间到达后,recv会返回错误,也就是-1,而此时的错误码是EAGAIN或者EWOULDBLOCK,POSIX.1-2001上允许两个任意一个出现都行,所以建议在判断错误码上两个都写上。
      如果socket是被对方用linger为0的形式关掉,也就是直接发RST的方式关闭的时候,recv也会返回错误,错误码是ENOENT
      还有一种经常在代码中常见的错误码,那就是EINTER,意思是系统在接收的时候因为收到其他中断信号而被迫返回,不算socket故障,应该继续接收。但是这种情况非常难再现,我尝试过一边一直在不停的发信号,一边用recv接收数据,也没有出现过。这种异常错误我附近只有一个朋友在用write的时候见到过一次,但是总是会有概率出现的,所以作为完善的程序必须对此错误进行特殊处理。

设置阻塞超时时间的方法如下:

int nNetTimeout=10000;//10秒,
    //设置发送超时
    setsockopt(m_socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
    //设置接收超时
    setsockopt(m_socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

或者:

    struct timeval timeout={3,0};//3s
    int ret=setsockopt(sock_fd,SOL_SOCKET,SO_SNDTIMEO,(const char*)&timeout,sizeof(timeout));
    int ret=setsockopt(sock_fd,SOL_SOCKET,SO_RCVTIMEO,(const char*)&timeout,sizeof(timeout));

(2)遇到的问题:阿里云服务器端口无法连接

我使用的是阿里云服务器,我创建 TCPServer程序监听端口后,用本地的client程序还是无法连接端口。

解决方法;阿里云服务器需要手动修改安全组策略才能使一个端口可以被访问。  在阿里云服务器中登录账号密码,在管理台中的  更多->网络与安全组->安全组配置。在下面的界面中添加新的端口安全组:

我为了使8900端口可以被访问,添加了如下安全组:

(3)遇到的问题:accept() : Invalid argument

问题描述:程序运行时运行到accpet()函数时有时会出错跳出程序(并不是总是会跳出),使用gdb 工具调试发现有时accept()函数的返回值是-1. 但不知道问题的具体原因。

//初始化的部分程序
socklen_t clilen;
struct sockaddr_in clientaddr;

研究之后 发现:问题就出在accept的第3个参数:必须为正数,如果没有初始化的话可能是正数可能是负数。

//accept函数:

connfd = accept(listenfd,(sockaddr *)&clientaddr,&clilen);

解决方法:在给第三个参数初始化的时候赋初值。

socklen_t clilen= sizeof(struct sockaddr);  
struct sockaddr_in clientaddr;

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值