C Socket通信编程

目录

1、socket概述

2、地址及顺序处理

3、函数介绍

4、使用实例


1、socket概述

  1、TCP协议通过三次握手协议建立连接

TCP协议通过三个报文段完成连接的建立,这个过程称为三次握手(three-way handshake),过程如下图所示。

 

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
一个完整的三次握手也就是: 请求---应答---再次确认。

对应的函数接口:
       

 

从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

  2、编程流程

2、地址及顺序处理

  1、地址结构相关处理

    struct socketaddr{

      unsigned short sa_family;

      char sa_data[14]

    }

    struct socketaddr_in{

      short int sa_family;//地址族,即使用什么样的地址,IPV4或者是IPV6

      unsigned short int sin_port;

      struct in_addr sin_addr;//存放IP地址

      unsigned char sin_zero[8]//填充0以保持也struct socketaddr 同样大小

    }

  2、数据存储优先顺序

    网络地址和主机地址转换

    #include <netinet/in.h>

    uint16_t htons(uint16_t host16bit)//主机地址向网络地址转换

    uint32_t htols(uint32_t host32bit)

    uint16_t ntohs(uint16_t net16bit)//网络地址向主机地址转换

    uint32_t ntohl(uint32_t net32bit)

    成功:返回要转换的字节序

    出错:-1

  3、地址格式转换

    将十进制表示的地址转换成二进制

    #include <arpa/inet.h>

    int inet_pton(int family,//协议类型

          const char *strptr,//要转化的值

          void *addrptr)//转化后的地址

    int inet_ntop(int family

           void *addrptr

           char *strptr

           size_t len)//转化后值的大小

    成功:0

    出错:-1

  4、名字地址转换

    gethostbyname()将主机名转换为IP地址

    gethostbyaddr()将IP地址转换为主机名

    #include <netbd.h>

    struct hostnet *gethostbyname(const char *honstname)

    成功:hostnet类型指针

    出错:-1

    int getaddrinfo(const char *hostname

            const char *service 

            const struct addrinfo *hints

            struct addrinfo **result)//返回的结果

    成功:0

    出错:-1

    struct hostnet {

      char *h_name;//主机名

      char **h_aliases;

      int h_addrtype;

      int h_length;

      char **h_addr_list;//指向IPV4的地址指针数组

    }


 

3、函数介绍  

    1、socket()  

      #include<sys/socket.h>

      int socket(int family,int type,int protocal)

      成功:非法套接字描述符

      出错:-1;

    2、bind()

      #include<sys/socket.h>

      int bind(int sockefd,struct sockaddr *my_addr,int addrlen);

      成功:0;

      出错:-1

    3、listen()

      #include<sys/socket.h>

      int listen(int sockfd,int backlog)

    4、accept()

      #include<sys/socket.h>

      int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

    5、connect()

      #include<sys/socket.h>

      int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);

      成功:0

      出错:-1

    6、send()

      int send(int sockfd,const void *msg,int len,int flags)

      成功:发送的字节数

     出错:-1

    7、recv()

      int recv(int sockfd,void *buff,int len,unsigned int flags)

      成功:接受的字节数

      出错:-1

    8、sendto()

      int sendto(int sockfd ,const void *msg,int len,unsigned int flags,struct sockaddr *to ,int * tolen)   

      成功:发送的字节数

      出错:-1

    9、recvfrom()

      int recvfrom(int sockfd ,const void *msg,int len,unsigned int flags,struct sockaddr *from ,int * tolen)   

      成功:接受的字节数

      出错:-1

 


 

 

4、简单实例

 

  1. /* File Name: server.c */  
  2. #include<stdio.h>  
  3. #include<stdlib.h>  
  4. #include<string.h>  
  5. #include<errno.h>  
  6. #include<sys/types.h>  
  7. #include<sys/socket.h>  
  8. #include<netinet/in.h>  
  9. #define DEFAULT_PORT 8000  
  10. #define MAXLINE 4096  
  11. int main(int argc, char** argv)  
  12. {  
  13.     int    socket_fd, connect_fd;  
  14.     struct sockaddr_in     servaddr;  
  15.     char    buff[4096];  
  16.     int     n;  
  17.     //初始化Socket  
  18.     if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){  
  19.     printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);  
  20.     exit(0);  
  21.     }  
  22.     //初始化  
  23.     memset(&servaddr, 0, sizeof(servaddr));  
  24.     servaddr.sin_family = AF_INET;  
  25.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。  
  26.     servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT  
  27.   
  28.     //将本地地址绑定到所创建的套接字上  
  29.     if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){  
  30.     printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);  
  31.     exit(0);  
  32.     }  
  33.     //开始监听是否有客户端连接  
  34.     if( listen(socket_fd, 10) == -1){  
  35.     printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);  
  36.     exit(0);  
  37.     }  
  38.     printf("======waiting for client's request======\n");  
  39.     while(1){  
  40. //阻塞直到有客户端连接,不然多浪费CPU资源。  
  41.         if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){  
  42.         printf("accept socket error: %s(errno: %d)",strerror(errno),errno);  
  43.         continue;  
  44.     }  
  45. //接受客户端传过来的数据  
  46.     n = recv(connect_fd, buff, MAXLINE, 0);  
  47. //向客户端发送回应数据  
  48.     if(!fork()){ /*紫禁城*/  
  49.         if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)  
  50.         perror("send error");  
  51.         close(connect_fd);  
  52.         exit(0);  
  53.     }  
  54.     buff[n] = '\0';  
  55.     printf("recv msg from client: %s\n", buff);  
  56.     close(connect_fd);  
  57.     }  
  58.     close(socket_fd);  
  59. }  

 

 

客户端:

 

  1. /* File Name: client.c */  
  2.   
  3. #include<stdio.h>  
  4. #include<stdlib.h>  
  5. #include<string.h>  
  6. #include<errno.h>  
  7. #include<sys/types.h>  
  8. #include<sys/socket.h>  
  9. #include<netinet/in.h>  
  10.   
  11. #define MAXLINE 4096  
  12.   
  13.   
  14. int main(int argc, char** argv)  
  15. {  
  16.     int    sockfd, n,rec_len;  
  17.     char    recvline[4096], sendline[4096];  
  18.     char    buf[MAXLINE];  
  19.     struct sockaddr_in    servaddr;  
  20.   
  21.   
  22.     if( argc != 2){  
  23.     printf("usage: ./client <ipaddress>\n");  
  24.     exit(0);  
  25.     }  
  26.   
  27.   
  28.     if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){  
  29.     printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);  
  30.     exit(0);  
  31.     }  
  32.   
  33.   
  34.     memset(&servaddr, 0, sizeof(servaddr));  
  35.     servaddr.sin_family = AF_INET;  
  36.     servaddr.sin_port = htons(8000);  
  37.     if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){  
  38.     printf("inet_pton error for %s\n",argv[1]);  
  39.     exit(0);  
  40.     }  
  41.   
  42.   
  43.     if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){  
  44.     printf("connect error: %s(errno: %d)\n",strerror(errno),errno);  
  45.     exit(0);  
  46.     }  
  47.   
  48.   
  49.     printf("send msg to server: \n");  
  50.     fgets(sendline, 4096, stdin);  
  51.     if( send(sockfd, sendline, strlen(sendline), 0) < 0)  
  52.     {  
  53.     printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);  
  54.     exit(0);  
  55.     }  
  56.     if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) {  
  57.        perror("recv error");  
  58.        exit(1);  
  59.     }  
  60.     buf[rec_len]  = '\0';  
  61.     printf("Received : %s ",buf);  
  62.     close(sockfd);  
  63.     exit(0);  
  64. }  

测试:

编译server.c

gcc -o server server.c

启动进程:

./server

显示结果:

======waiting for client's request======

并等待客户端连接。

编译 client.c

gcc -o client server.c

客户端去连接server:

./client 127.0.0.1 

等待输入消息

发送一条消息,输入:c++

此时服务器端看到:

客户端收到消息:

 

其实可以不用client,可以使用telnet来测试:

telnet 127.0.0.1 8000

 

posted on 2015-01-19 11:03  Marty at HDU  阅读(563)  评论(0编辑  收藏  举报

导航