TCP服务端-客户端(客户端具有重连功能)

/*
先看TCP服务器端的程序:
*/
#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 PORT 10000

int main(int argc, char *argv[]) 
{ 
 int sockfd,new_fd; 
 struct sockaddr_in server_addr; 
 struct sockaddr_in client_addr; 
 int sin_size; 
 int nbytes;
 char buffer[1024];
 

 /* 服务器端开始建立sockfd描述符 */ 
 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 
 { 
  fprintf(stderr,"Socket error:%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描述符到IP地址 */ 
 if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) 
 { 
  fprintf(stderr,"Bind error:%s\n\a",strerror(errno)); 
  exit(1); 
 } 

 /* 设置允许连接的最大客户端数 */ 
 if(listen(sockfd,5)==-1) 
 { 
  fprintf(stderr,"Listen error:%s\n\a",strerror(errno)); 
  exit(1); 
 } 

 while(1) 
 { 
	  /* 服务器阻塞,直到客户程序建立连接 */ 
	  memset(buffer, '\0', sizeof(buffer));
	  sin_size=sizeof(struct sockaddr_in); 
	  if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) 
	  { 
	   fprintf(stderr,"Accept error:%s\n\a",strerror(errno)); 
	   exit(1); 
	  } 
	  fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); 
	  
	  if((nbytes=read(new_fd,buffer,1024))==-1) 
	  { 
	   fprintf(stderr,"Read Error:%s\n",strerror(errno)); 
	   exit(1); 
	  }   
	  buffer[nbytes]='\0';
	  printf("Server received %s\n",buffer);
 } 

 /* 结束通讯 */ 
 close(sockfd); 
 exit(0); 
} 
</pre><pre code_snippet_id="360375" snippet_file_name="blog_20140523_3_143696" name="code" class="html">/*
再看客户端的程序:
*/
#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 PORT 10000


int main(int argc, char *argv[]) 
{ 
 int sockfd; 
 char buffer[1024] = "hello"; 
 struct sockaddr_in server_addr; 


 /* 客户程序开始建立 sockfd描述符 */ 
 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 
 { 
  fprintf(stderr,"Socket Error:%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);  
 inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
 
 again:
 /* 客户程序发起连接请求 */ 
 if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) 
 { 
  fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); 
  goto again; 
 } 




 if(write(sockfd,buffer,strlen(buffer)) <= 0)
 {
<span style="white-space:pre">	</span>goto again; 
 } 
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>return 0;
} 

说明:

inet_ntoa在64位机器上出错

inet_ntoa用法如下:

[html]  view plain copy
  1. char *inet_ntoa(struct in_addr in);  
就是将struct in_addr结构转换为IP地址的形式,struct in_addr这个结构应该不陌生吧,它的定义如下:


[cpp]  view plain copy
  1. struct in_addr{  
  2.        unsigned long s_addr;  
  3. }  
  4. struct sockaddr_in {  
  5.        short int sin_family;  
  6.        unsigned short int sin_port;   
  7.        struct in_addr sin_addr;  
  8.        unsigned char sin_zero[8];  
  9. };  

在服务器端使用accept函数之后,会得到客户端连接的struct sockaddr结构,然后将其转换成struct sockaddr_in结构,此时可以在服务器端得到客户端连接的IP和端口数据。

这时用这个函数有一个问题是:如果在64位的机器上,使用

[cpp]  view plain copy
  1. char* tmp = inet_ntoa(sin->sin_addr);  
之后,对tmp进行操作,会出现断错误,但在32位机器上没有问题,原因是64位时inet_ntoa返回值是一个整型。

在网上找的两种解决办法:

  1. 在使用的文件中,引用#include <arpa/inet.h>头文件。
  2. 直接使用inet_ntop函数。

inet_ntop的说明如下:

[html]  view plain copy
  1. NAME  
  2.        inet_ntop - Parse network address structures  
  3.   
  4. SYNOPSIS  
  5.        #include <sys/types.h>  
  6.        #include <sys/socket.h>  
  7.        #include <arpa/inet.h>  
  8.   
  9.        const char *inet_ntop(int af, const void *src,  
  10.                              char *dst, socklen_t cnt);  
  11.   
  12. DESCRIPTION  
  13.        This  function converts the network address structure src in the af address family into a char-  
  14.        acter string, which is copied to a character buffer dst, which is cnt bytes long.  
  15.   
  16.        inet_ntop(3)  extends  the  inet_ntoa(3)  function  to  support  multiple   address   families,  
  17.        inet_ntoa(3)  is  now  considered  to  be  deprecated  in favor of inet_ntop(3).  The following  
  18.        address families are currently supported:  
  19.   
  20.        AF_INET  
  21.               src points to a struct in_addr (network byte order format) which is converted to an IPv4  
  22.               network address in the dotted-quad format, "ddd.ddd.ddd.ddd".  The buffer dst must be at  
  23.               least INET_ADDRSTRLEN bytes long.  
  24.   
  25.        AF_INET6  
  26.               src points to a struct in6_addr (network byte order format) which is converted to a rep-  
  27.               resentation of this address in the most appropriate IPv6 network address format for this  
  28.               address.  The buffer dst must be at least INET6_ADDRSTRLEN bytes long.  
  29.   
  30. RETURN VALUE  
  31.        inet_ntop() returns a non-null pointer to dst.  NULL is returned if there was  an  error,  with  
  32.        errno set to EAFNOSUPPORT if af was not set to a valid address family, or to ENOSPC if the con-  
  33.        verted address string would exceed the size of dst given by the cnt argument.  
  34.   
  35. CONFORMING TO  
  36.        POSIX.1-2001.  Note that RFC 2553 defines a prototype where the last parameter cnt is  of  type  
  37.        size_t.  Many systems follow RFC 2553.  Glibc 2.0 and 2.1 have size_t, but 2.2 has socklen_t.  

因此修改为:

char IPdes[16]="";
inet_ntop(AF_INET, (void *)&client_addr.sin_addr, IPdes, 16);
fprintf(stderr,"Server get connection from %s\n",IPdes);


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值