linux-c-tcp服务带超时处理的c/s

本文介绍了一个简单的TCP服务器和客户端的实现案例,包括源代码及运行示例。通过该案例可以了解如何利用socket进行网络通信的基本原理,特别是如何读取和发送数据的过程。

1.server

deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcps

server wait....

............................

server read :deepfuture.iteye.com

 

server send :hello

.....

server read :deepfuture.iteye.com

 

server send :hello

2.client
deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc
client send....
client send :deepfuture.iteye.com

client read :hello

deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc
client send....
client send :deepfuture.iteye.com

client read :hello

deepfuture@deepfuture-laptop:~/private/mytest$ 
3.source
1)server
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//deepfuture.iteye.com
ssize_t readn(int fd,void *ptr,size_t maxcn){//读取n个字符,maxc为读取的数目
    size_t noreadcn,readcn;
    char *buf=ptr;

    
    
    noreadcn=maxcn;
    while(noreadcn>0){
       if ( (readcn=read(fd,buf,noreadcn))<0){//读数据
    
          if (errno==EINTR) {//数据读取前,操作被信号中断
             perror("中断错误");
             readcn=0;           
          }
          else {return -1;}//无法修复错误,返回读取失败
       }
       else if(readcn==0) break;//EOF
       
       
       noreadcn-=readcn;//读取成功,但是如果读取的字符数小于maxc,则继续读,因为可能数据还会继续通过网络送过来    
       buf+=readcn;  
       if (*buf==0) break;//如果读到字符串结尾标志则退出,必须有这句,否则会死循环
       }  


     
    return (maxcn-noreadcn);
}

ssize_t  writen(int fd,void *ptr,size_t maxcn){//写入n个字符
    size_t nowritecn,writecn;
    char *buf=ptr;

    
    nowritecn=maxcn;
    while(nowritecn>0){
       if((writecn=write(fd,buf,nowritecn))<=0){//写数据
       
          if (errno==EINTR) {//数据写前,操作被信号中断
             perror("中断错误");
             writecn=0;             
          }
          else {return -1;}//无法修复错误,返回读取失败
       }

      
       nowritecn-=writecn;
       buf+=writecn;  

       } 

       return (maxcn-nowritecn);
}

int main(void){
    int fd;
    int addresslen;
    struct sockaddr_in address;//地址信息结构
    int pid;
    int rc;
    fd_set fdset;
    


                  
    //建立socket
    fd=socket(AF_INET,SOCK_STREAM,0);//fd为socket
    if (fd==-1){//错误,类型从errno获得
        perror("error");//perror先输出参数,后跟":"加空格,然后是errno值对应的错误信息(不是错误代码),最后是一个换行符。        
    }
    
    //bind 到socket fd    
    address.sin_family=AF_INET;//IPV4协议,AF_INET6是IPV6
    address.sin_addr.s_addr=htonl(INADDR_ANY);//l表示32位,htonl能保证在不同CPU的相同字节序
    address.sin_port=htons(1253);//端口号,s表示16位
    addresslen=sizeof(address);
    

    bind(fd,(struct sockaddr *)&address,addresslen);//bind
    
           //建立socket队列,指定最大可接受连接数
           rc=listen(fd,32);//最多接收32个连接,开始监听
           //int listen(int sockfd, int backlog)返回:0──成功, -1──失败
           //内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接
           if (rc==-1) {
              perror("listen error");//监听失败
              exit(1);
           }
           printf("server wait....\n");           
           while(1){

              struct sockaddr_in clientaddress;
              int address_len;
              int client_sockfd;
              char mybuf[100];    
              char *buf="hello\n";  
              struct timeval timeout;//超时结构体
              //超时为2秒
              timeout.tv_sec=1;
              timeout.tv_usec=0;
              //设置fdset
              FD_ZERO(&fdset);//清除fdset
              FD_CLR(fd,&fdset);//清除fd的标志
              FD_SET(fd,&fdset);//设置标志
              //select
              if ((select(fd+1,&fdset,NULL,NULL,&timeout))<0){
                  perror("select error");
                  fflush(stdout);              
              }
              //等待连接,使用新的进程或线程来处理连接

              fflush(stdout);     
              address_len=sizeof(clientaddress);              
              if(FD_ISSET(fd,&fdset)){
                  //如果有连接到来
                 client_sockfd=accept(fd,(struct sockaddr *)&clientaddress,&address_len);//client_sockfd可理解为一个文件句柄,能用read和write操作。client_address是客户端信息结构 deepfuture.iteye.com
              
              //fork进程来处理每个客户的连接      
            	  pid=fork();
           	   if (pid<0){//错误
            	    printf("error:%s\n",strerror(errno));//strerror将errno映射为一个错误信息串 deepfuture.iteye.com
              		close(client_sockfd);
              	  	exit(1); 
            	}   

             	 if (pid==0){ //子进程处理每个客户端的数据            
             	     close(fd);//子进程关闭不需要它处理的监听资源

             		  //读取数据 deepfuture.iteye.com
                	  bzero(mybuf,100);                   
             	     readn(client_sockfd,(void *)mybuf,100);
                	  printf("\nserver read :%s",mybuf);                  
                  	 //发送数据                  
               	 	  writen(client_sockfd,(void *)buf,strlen(buf)+1);               
               		   printf("\nserver send :%s",buf);                
               		   close(client_sockfd);
               		   exit(0);
           		 }
           		  else {//父进程
                		  close(client_sockfd);//父进程不处理客户端连接,因此关闭,但并不意味着把子进程的处理句柄关闭,因为子进程继承了父进程的client_sockfd资源         deepfuture.iteye.com     
            	 }                               
            }else{
                  printf(".");
                  fflush(stdout);
            }
       }
 }
 2) client
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//deepfuture.iteye.com
ssize_t readn(int fd,void *ptr,size_t maxcn){//读取n个字符,maxc为读取的数目
    size_t noreadcn,readcn;
    char *buf=ptr;
    
    
    noreadcn=maxcn;
    while(noreadcn>0){
       if ( (readcn=read(fd,buf,noreadcn))<0){//读数据
    
          if (errno==EINTR) {//数据读取前,操作被信号中断 deepfuture.iteye.com
             perror("中断错误");
             readcn=0;            
          }
          else {return -1;}//无法修复错误,返回读取失败
       }
       else if(readcn==0) break;//EOF deepfuture.iteye.com
           
       noreadcn-=readcn;//读取成功,但是如果读取的字符数小于maxc,则继续读,因为可能数据还会继续通过网络送过来    
       buf+=readcn;   
        if (*buf==0) break;    //如果读到字符串结尾标志则退出,必须有这句,否则会死循环  deepfuture.iteye.com
       }   

    return (maxcn-noreadcn);
}

ssize_t writen(int fd,void *ptr,size_t maxcn){//写入n个字符
    size_t nowritecn,writecn;
    char *buf=ptr;
    
    nowritecn=maxcn;
    while(nowritecn>0){
       if((writecn=write(fd,buf,nowritecn))<=0){//写数据
          if (errno==EINTR) {//数据写前,操作被信号中断
             perror("中断错误");
             writecn=0;             
          }
          else {return -1;}//无法修复错误,返回读取失败
       }
    
       nowritecn-=writecn;
       buf+=writecn; 

       }  
       return (maxcn-nowritecn);
}

int main(void){
    int fd;
    int addresslen;
    struct sockaddr_in address;//地址信息结构 deepfuture.iteye.com
    int pid;
    char mybuf[100];        
    char *buf="deepfuture.iteye.com\n";
    int rc;


    fd=socket(AF_INET,SOCK_STREAM,0);//建立socket
    if (fd==-1){//错误,类型从errno获得
        perror("error");//perror先输出参数,后跟":"加空格,然后是errno值对应的错误信息(不是错误代码),最后是一个换行符。    deepfuture.iteye.com     
    }
  
    printf("client send....\n");
    fflush(stdout);
    
    //连接
    address.sin_family=AF_INET;//IPV4协议,AF_INET6是IPV6 deepfuture.iteye.com
    address.sin_addr.s_addr=inet_addr("127.0.0.1");//l表示32位,htonl能保证在不同CPU的相同字节序
    address.sin_port=htons(1253);//端口号,s表示16位 deepfuture.iteye.com
    addresslen=sizeof(address);        
    rc=connect(fd,(struct sockaddr *)&address,addresslen);//连接服务器 deepfuture.iteye.com
    if (rc==-1){//rc=0成功,rc=-1失败 deepfuture.iteye.com
      perror("连接错误");
      exit(1);
    }
    //发送数据 
    writen(fd,(void *)buf,strlen(buf)+1);
    printf("client send :%s\n",buf);      
    //读取数据
    bzero(mybuf,100);  
    readn(fd,(void *)mybuf,100); 
    printf("client read :%s\n",mybuf); 
    close(fd);
    exit(0);                

 }
 
<think>好的,我现在需要帮助用户查找在Linux环境下使用C语言实现TCP网络编程的教程和示例代码。用户提供了几个引用,看起来是关于Socket编程的,我需要结合这些引用和我的知识来组织一个清晰的回答。 首先,我需要回忆一下TCP编程的基本步骤。通常分为服务端和客户端。服务端的步骤是创建socket,绑定地址,监听连接,接受连接,然后进行通信。客户端则是创建socket,连接到服务端,然后通信。关闭连接是双方都需要做的。 接下来,看看用户提供的引用内容。引用[4]详细说明了服务端的步骤:socket(), bind(), listen(), accept(), read()/write(), close()。客户端部分在引用[3]中提到了socket、填写服务端地址、connect,封装成函数。引用[2]中的示例代码是关于IP地址转换的,可能对理解地址处理有帮助。引用[1]提到用户之前写过C语言实现TCP连接的文章,但现在想重新整理。 我需要将这些信息整合成一个教程,分步骤说明服务端和客户端的实现,并给出示例代码。同时,需要确保代码符合C语言在Linux下的标准,使用正确的头文件和函数调用。例如,服务端代码可能包括创建socket,设置地址结构体,绑定,监听,接受连接,读写数据。客户端则是创建socket,连接,然后通信。 另外,需要注意错误处理,比如检查每个系统调用的返回值,这在示例代码中可能需要简化,但用户可能需要知道实际应用中应该处理错误。例如,socket()返回-1表示失败,bind()也可能出错,需要处理。 然后,用户要求生成相关问题。我需要考虑用户可能对TCP编程的哪些方面有疑问,比如多客户端处理、阻塞与非阻塞、错误处理等。可能的问题包括如何同时处理多个客户端连接,如何设置超时,或者TCP与UDP的区别等。 最后,确保回答结构清晰,分步骤说明,代码部分用代码块表示,并正确引用用户提供的引用来源。例如,服务端的步骤引用[4],客户端的函数封装引用[3],IP转换的示例引用[2]。 现在需要组织这些内容,确保符合用户给出的格式要求,如使用中文,行内公式正确(虽然这里可能用不到),独立公式单独成段。不过这里主要是代码和步骤说明,所以重点放在代码的正确性和步骤的清晰性上。 可能还需要验证示例代码是否正确。比如,服务端代码是否正确使用socket(), bind(), listen(), accept()等函数,客户端是否正确使用connect()。确保示例代码中的函数参数正确,比如地址结构体使用struct sockaddr_in,正确设置地址族、端口、IP地址,并使用htonl, htons等函数转换字节序。 总之,步骤是:概述TCP编程步骤,分服务端和客户端,给出示例代码,引用相关引用,然后生成相关问题。</think>### Linux C语言TCP网络编程实现教程 在Linux环境下使用C语言实现TCP通信,主要分为**服务端**和**客户端**两部分。以下是具体步骤和示例代码: --- #### **服务实现步骤** [^4] 1. **创建Socket**:使用`socket()`函数创建套接字。 2. **绑定地址**:通过`bind()`将套接字与本地IP和端口绑定。 3. **监听连接**:调用`listen()`进入监听状态,等待客户端连接。 4. **接受连接**:使用`accept()`接收客户端请求,返回新的通信套接字。 5. **数据交互**:通过`read()`/`write()`进行通信。 6. **关闭连接**:使用`close()`释放资源。 **示例代码(服务端)**: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8080 int main() { int server_fd, new_socket; struct sockaddr_in address; int addrlen = sizeof(address); char buffer[1024] = {0}; // 1. 创建Socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // 2. 绑定地址 if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 3. 监听连接 if (listen(server_fd, 3) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } // 4. 接受连接 if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) { perror("accept failed"); exit(EXIT_FAILURE); } // 5. 数据交互 read(new_socket, buffer, 1024); printf("Received: %s\n", buffer); send(new_socket, "Hello from server", 17, 0); // 6. 关闭连接 close(new_socket); close(server_fd); return 0; } ``` --- #### **客户端实现步骤** [^3] 1. **创建Socket**:使用`socket()`函数。 2. **设置服务端地址**:填充服务端IP和端口。 3. **发起连接**:调用`connect()`连接到服务端。 4. **数据交互**:通过`send()`/`recv()`通信。 5. **关闭连接**:释放资源。 **示例代码(客户端)**: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define SERVER_IP "127.0.0.1" #define PORT 8080 int main() { int sock = 0; struct sockaddr_in serv_addr; char buffer[1024] = {0}; // 1. 创建Socket if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // 2. 转换IP地址格式(参考引用[2]) if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) { perror("invalid address"); exit(EXIT_FAILURE); } // 3. 发起连接 if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { perror("connection failed"); exit(EXIT_FAILURE); } // 4. 数据交互 send(sock, "Hello from client", 17, 0); read(sock, buffer, 1024); printf("Server response: %s\n", buffer); // 5. 关闭连接 close(sock); return 0; } ``` --- #### **关键函数说明** - `socket()`:创建套接字,参数`AF_INET`表示IPv4,`SOCK_STREAM`表示TCP协议。 - `bind()`:绑定IP和端口时需注意字节序转换(如`htons()`)[^2]。 - `accept()`:阻塞等待客户端连接,返回新的套接字用于通信。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值