linux下socket和MySQL数据库编程

来源:互联网 发布:windows文件丢失 编辑:程序博客网 时间:2024/06/05 00:12


一、基本socket函数

Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也有一个类似于打
开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
1、socket函数
syntax:
   int socket(int domain, int type, int protocol);
功能说明:
   调用成功,返回socket文件描述符;失败,返回-1,并设置errno
参数说明:
  domain指明所使用的协议族,通常为PF_INET,表示TCP/IP协议;
  type参数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字
  protocol通常赋值"0"。
  两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。socket数据结构中包含这五种信息。
2、bind函数
syntax:  
   int bind(int sock_fd,struct sockaddr_in *my_addr, int addrlen);
功能说明:
   将套接字和指定的端口相连。成功返回0,否则,返回-1,并置errno.
参数说明:
    sock_fd是调用socket函数返回值,
  my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
  struct sockaddr_in结构类型是用来保存socket信息的:
  struct sockaddr_in {
  short int sin_family;
  unsigned short int sin_port;
  struct in_addr sin_addr;
  unsigned char sin_zero[8];
  };
    addrlen为sockaddr的长度。
3、connect函数
syntax:  
    int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
功能说明:
   客户端发送服务请求。成功返回0,否则返回-1,并置errno。
参数说明:
   sock_fd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是结构sockaddr_in的长度。
4、listen函数
syntax:
   int listen(int sock_fd, int backlog);
功能说明:
   等待指定的端口的出现客户端连接。调用成功返回0,否则,返回-1,并置errno.
参数说明:
   sock_fd 是socket()函数返回值;
   backlog指定在请求队列中允许的最大请求数
5、accecpt函数
syntax:  
   int accept(int sock_fd, struct sockadd_in* addr, int addrlen);
功能说明:
   用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:
   sock_fd是被监听的socket描述符,
   addr通常是一个指向sockaddr_in变量的指针,
   addrlen是结构sockaddr_in的长度。
6、write函数
syntax:
    ssize_t write(int fd,const void *buf,size_t nbytes)
功能说明:
    write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量.
    在网络程序中,当我们向套接字文件描述符写时有俩种可能:
      1)write的返回值大于0,表示写了部分或者是全部的数据.
      2)返回的值小于0,此时出现了错误.需要根据错误类型来处理.
        如果错误为EINTR表示在写的时候出现了中断错误.
        如果错误为EPIPE表示网络连接出现了问题.
7、read函数
syntax:
    ssize_t read(int fd,void *buf,size_t nbyte)
函数说明:
    read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.
    如果错误为EINTR说明读是由中断引起的,
    如果错误是ECONNREST表示网络连接出了问题.
8、close函数
syntax:
int close(sock_fd);
说明:
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
函数运行成功返回0,否则返回-1
二、socket编程的其他函数说明
1、 网络字节顺序及其转换函数
1) 网络字节顺序
每一台机器内部对变量的字节存储顺序不同,而网络传输的数据是一定要统一顺序的。所以对内部字节表示顺序与网络字节顺序不同的机器,
一定要对数据进行转换,从程序的可移植性要求来讲,就算本机的内部字节表示顺序与网络字节顺序相同也应该在传输数据以前先调用数据转换函数,
以便程序移植到其它机器上后能正确执行。真正转换还是不转换是由系统函数自己来决定的。
2) 有关的转换函数
* unsigned short int htons(unsigned short int hostshort):
主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes
* unsigned long int htonl(unsigned long int hostlong):
主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes
* unsigned short int ntohs(unsigned short int netshort):
网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes
* unsigned long int ntohl(unsigned long int netlong):
网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes
注:以上函数原型定义在netinet/in.h里
2、IP地址转换
有三个函数将数字点形式表示的字符串IP地址与32位网络字节顺序的二进制形式的IP地址进行转换
(1) unsigned long int inet_addr(const char * cp):该函数把一个用数字和点表示的IP地址的字符串转换成一个无符号长整型,如:struct sockaddr_in ina
ina.sin_addr.s_addr=inet_addr("202.206.17.101")
该函数成功时:返回转换结果;失败时返回常量INADDR_NONE,该常量=-1,二进制的无符号整数-1相当于255.255.255.255,这是一个广播地址,所以在程序中调用iner_addr()时,一定要人为地对调用失败进行处理。由于该函数不能处理广播地址,所以在程序中应该使用函数inet_aton()。
(2)int inet_aton(const char * cp,struct in_addr * inp):此函数将字符串形式的IP地址转换成二进制形式的IP地址;成功时返回1,否则返回0,转换后的IP地址存储在参数inp中。
(3) char * inet_ntoa(struct in-addr in):将32位二进制形式的IP地址转换为数字点形式的IP地址,结果在函数返回值中返回,返回的是一个指向字符串的指针。
3、字节处理函数
Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI C提供的函数。
以b开头的函数有:
(1) void bzero(void * s,int n):将参数s指定的内存的前n个字节设置为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n):从参数src指定的内存区域拷贝指定数目的字节内容到参数dest指定的内存区域。
(3) int bcmp(const void * s1,const void * s2,int n):比较参数s1指定的内存区域和参数s2指定的内存区域的前n个字节内容,如果相同则返回0,否则返回非0。
注:以上函数的原型定义在strings.h中。
以mem开头的函数有:
(1) void * memset(void * s,int c,size_t n):将参数s指定的内存区域的前n个字节设置为参数c的内容。
(2) void * memcpy(void * dest,const void * src,size_t n):功能同bcopy(),区别:函数bcopy()能处理参数src和参数dest所指定的区域有重叠的情况,memcpy()则不能。
(4) int memcmp(const void * s1,const void * s2,size_t n):比较参数s1和参数s2指定区域的前n个字节内容,如果相同则返回0,否则返回非0。

注:以上函数的原型定义在string.h中。


二、程序

1、client.c

/*client.c  linux 下socket网络编程简例  - 客户端程序 服务器端口设为 0x8888   (端口和地址可根据实际情况更改,或者使用参数传入) 服务器地址设为 192.168.1.104 作者:golden1314521#gmail.com (将#换为@) */    #include <stdlib.h>  #include <sys/types.h>  #include <stdio.h>  #include <sys/socket.h>  #include <linux/in.h>  #include <string.h>    int main()  {      int cfd; /* 文件描述符 */      int recbytes;      int sin_size;      char buffer[1024]={0};    /* 接受缓冲区 */      struct sockaddr_in s_add,c_add; /* 存储服务端和本端的ip、端口等信息结构体 */      unsigned short portnum=0x8888;  /* 服务端使用的通信端口,可以更改,需和服务端相同 */        printf("Hello,welcome to client !\r\n");      /* 建立socket 使用因特网,TCP流传输 */      cfd = socket(AF_INET, SOCK_STREAM, 0);      if(-1 == cfd)      {          printf("socket fail ! \r\n");          return -1;      }      printf("socket ok !\r\n");      /* 构造服务器端的ip和端口信息,具体结构体可以查资料 */      bzero(&s_add,sizeof(struct sockaddr_in));      s_add.sin_family=AF_INET;      s_add.sin_addr.s_addr= inet_addr("10.109.16.157"); /* ip转换为4字节整形,使用时需要根据服务端ip进行更改 */        s_add.sin_port=htons(portnum); /* 这里htons是将short型数据字节序由主机型转换为网络型,其实就是将2字节数据的前后两个字节倒换,和对应的ntohs效果、实质相同,只不过名字不同。htonl和ntohl是操作的4字节整形。将0x12345678变为0x78563412,名字不同,内容两两相同,一般情况下网络为大端,PPC的cpu为大端,x86的cpu为小端,arm的可以配置大小端,需要保证接收时字节序正确. */        printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port); /* 这里打印出的是小端和我们平时看到的是相反的。 */        /* 客户端连接服务器,参数依次为socket文件描述符,地址信息,地址结构大小 */      if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))      {          printf("connect fail !\r\n");          return -1;      }        printf("connect ok !\r\n");      /*连接成功,从服务端接收字符*/     if(-1 == write(cfd,"getNameList",32))    {        printf("write fail!\r\n");        return -1;    }    printf("write request to server is ok\n");     if(-1 == (recbytes = read(cfd,buffer,1024)))      {          printf("read data fail !\r\n");          return -1;      }      printf("read ok\r\nREC:\r\n");        buffer[recbytes]='\0';      printf("%s\r\n",buffer);        //getchar(); /* 此句为使程序暂停在此处,可以使用netstat查看当前的连接 */      close(cfd); /* 关闭连接,本次通信完成 */      return 0;    }  

2、server.c

/*erver.c  linux 下socket网络编程简例  - 服务端程序 服务器端口设为 0x8888   (端口和地址可根据实际情况更改,或者使用参数传入) 服务器地址设为 作者:golden1314521#gmail.com (将#换为@) */    #include <stdlib.h>   #include <sys/types.h>   #include <stdio.h>   #include <sys/socket.h>   #include <linux/in.h>   #include <string.h>#include <mysql.h>//#include <stdio.h>//#include <locale.h>#include <string.h>#include <assert.h>int init_sfp(unsigned short);void getdata(char *);  int main()  {      int sfp;       unsigned short port = 0x8888;           if(-1 == (sfp=init_sfp(port)))      {          printf("init_socket fail ! \r\n");          return -1;      }      if(-1 == listen(sfp,5))      {          printf("listen fail !\r\n");          return -1;      } else {        printf("Server started,port:%d\r\n",port);      }          while(1)      {                  struct sockaddr_in c_add;      int sin_size = sizeof(struct sockaddr_in);  int nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);          printf("\n**********************************************\n\n");        char buffer[1024]={0};    /* 接受缓冲区 */        int recbytes;        if(-1 == nfp)          {              printf("accept fail !\r\n");              return -1;          }          printf("accept ok!\r\nServer start get connect from %#x : %#x\r\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));            if(-1 == (recbytes = read(nfp,buffer,1024)))        {            printf("read data fail !\r\n");            return -1;        }        printf("read ok\rthe num of bytes is %d:\r\n",recbytes);        buffer[recbytes]='\0';        printf("request from client : %s\r\n",buffer);        /* 这里使用write向客户端发送信息,也可以尝试使用其他函数实现 */        if(0==strcmp(buffer,"getNameList")) {            memset(buffer,0,1024);            getdata(buffer);            if(-1 == write(nfp,buffer,1024))              {                  printf("write fail!\r\n");                  return -1;            }             printf("write ok!\r\n");          }         close(nfp);          printf("\n**********************************************\n\n");      }      close(sfp);      return 0;  }  int init_sfp(unsigned short port) {    int sfp;    unsigned short portnum=port;/*端服务器使用端口 */      struct sockaddr_in s_add;    //printf("Hello,welcome to my server !\r\n%d\n",portnum);      sfp = socket(AF_INET, SOCK_STREAM, 0);      if(-1 == sfp)      {            return -1;      }          /* 填充服务器端口地址信息,以便下面使用此地址和端口监听 */      bzero(&s_add,sizeof(struct sockaddr_in));      s_add.sin_family=AF_INET;      s_add.sin_addr.s_addr=htonl(INADDR_ANY); /* 这里地址使用全0,即所有 */      s_add.sin_port=htons(portnum);      /* 使用bind进行绑定端口 */      if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))      {          return -1;      }          return sfp;  }   void getdata(char *packets){    MYSQL *conn;    MYSQL_RES *res;    MYSQL_ROW row;       char *server = "localhost";    char *user = "root";    char *password = "jobs1991"; /* 此处改成你的密码 */    char *database = "moviedatabase";    conn = mysql_init(NULL);   /* Connect to database */   if (!mysql_real_connect(conn, server,          user, password, database, 0, NULL, 0)) {      fprintf(stderr, "%s\n", mysql_error(conn));     // return 1;   }   /* send SQL query */      int utf8;   utf8=mysql_query(conn,"set character_set_results=utf8");   printf("utf8=%d\n",utf8);   assert(utf8==0);          //其实你需要的就是这行上面的部分 然后你就什么都会了  ^_^    这四行代码以上和以下的代码几乎都是没有意义的,因为这不是个问题   //mysql_set_character_set(conn,"utf-8");   if (mysql_query(conn, "SELECT name from streamMovieList")) {      fprintf(stderr, "%s\n", mysql_error(conn));      //return 1;   }    res = mysql_use_result(conn);   /* output table name */   printf("MySQL Tables in mysql database:\n");   while ((row = mysql_fetch_row(res)) != NULL)   {      strcat(packets,row[0]);      //printf("%s \n", row[0]);   }      mysql_free_result(res);   mysql_close(conn);   }



1 0