Linux網絡編程基礎:TCP服務器程序實現

編程步驟

1)調用Socket函數創建套接字文件
2)調用bind函數綁定ip和端口
3)調用listen函數將套接字文件轉爲被動描述符
4)調用accept函數監聽客戶連接
5)調用send函數發送數據
6)調用recv函數接收數據
7)調用shutdown函數結束連接
示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>

#define  SIP "192.168.239.128"  //存放服務器固定ip的宏
#define  SPROT 5006  //存放服務器進程固定端口的宏

/*封裝應用層數據,目前要發送的數據爲學生信息*/
typedef struct data
{
   unsigned int stu_num;
   char stu_nam[50];
}Data;

void print_err(char* str,int line,int err_no)  //報錯函數
{
    printf("%d %s: %s\n",line,str,strerror(err_no));
    exit(-1);
}

int cfd = -1;/*通信套接字文件*/

void signal_fun(int signo)
{
     if(signo == SIGINT)
     {
         //斷開連接
         //close(cfd);
         shutdown(cfd,SHUT_RDWR);
         exit(0);
     }
}
/*次線程用於接收客戶端數據 */
void* pth_fun(void* pth_arg)
{
    Data stu_cdata = {0};
    int ret = -1;
    while(1)
    {
         bzero(&stu_cdata,sizeof(stu_cdata));
         ret = recv(cfd,(void*)&stu_cdata,sizeof(stu_cdata),0);
         if(ret == -1)  print_err("recv error",__LINE__,errno);
         else if(ret>0)
         {
         printf("student number:%d\n",ntohl(stu_cdata.stu_num));
         printf("student name:%s\n",stu_cdata.stu_nam);
         }
      }
}

int main()
{
    int ret=-1;
    int sockfd=-1;

    signal(SIGINT,signal_fun);

    /*創建使用TCP協議的套接字文件 */
    sockfd = socket(PF_INET,SOCK_STREAM,0 );
    if(sockfd == -1) print_err("socket error",__LINE__,errno);

    /*調用bind綁定套接字文件/ip/端口*/
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(SPROT);
    saddr.sin_addr.s_addr = inet_addr(SIP);
    ret = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1)  print_err("bind error",__LINE__,errno);

    /*將套接字文件從主動文件描述符變爲被動文件描述符,用於被動監聽客戶的連接 */
    ret = listen(sockfd,3);
    if(ret == -1) print_err("listen error",__LINE__,errno);

   /*調用accept函數 被動監聽客戶端的三次握手連接 */
   struct sockaddr_in clnaddr = {0};
   int clnaddr_size = sizeof(clnaddr);
   cfd = accept(sockfd,(struct sockaddr *)&clnaddr,&clnaddr_size);
   if(cfd == -1) print_err("accept error",__LINE__,errno);

   /*打印客戶端的IP和端口號 注意要進行端序轉換 */
   printf("clint_port = %d\n clint_ip = %s\n",ntohs(clnaddr.sin_port),inet_ntoa(clnaddr.sin_addr));

   /*創建一個次線程,用於接收客戶端的信息*/
   pthread_t tid;
   ret = pthread_create(&tid,NULL,pth_fun,NULL);
   if(ret != 0)  print_err("pth_create fail",__LINE__,ret);

   /*服務器循環發送數據 */
   Data stu_data = {0};
   int tmp;
   while(1)
   {
       bzero(&stu_data,sizeof(stu_data));
       printf("please input student number:\n");
       scanf("%d",&tmp);
       /*主機端序轉爲網絡端序 */
       stu_data.stu_num = htonl(tmp);
       /*char類型的數據不需要轉換端序 */
       printf("please input student name:\n");
       scanf("%s",stu_data.stu_nam);
       /*用send函數發送數據 */
       ret = send(cfd,(void *)&stu_data,sizeof(stu_data),0);
       if(ret == -1)  print_err("send error",__LINE__,errno);
     }
   return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章