Linux系统C语言socket tcp套接字编程

1.套接字的地址结构:

  

 1 typedef uint32_t in_addr_t;  //32位无符号整数,用于表示网络地址
 2 struct in_addr{
 3     in_addr_t s_addr;  //32位 ipv4 地址
 4 }
 5 typedef uint16_t in_port_t;  //16位无符号整数,用于表示端口号
 6 struct sockaddr_in{
 7     uint8_t sin_len;      //结构长度,8位无符号整数
 8     sa_family_t sin_family;  //套接字地址族
 9     in_port_t sin_port;    //16位 TCP 或 UDP 端口号
10     struct in_addr sin_addr;  //32位 ipv4 地址
11     char sin_zero[8];    //暂时不用。总置为0
12 }

 

2.创建套接字函数 socket

int socket(int family , int type , int protocol)

  • family : 说明网络程序采用的通信协议族(比如 AF_INET 对应于 TCP/IP 协议族)
  • type : 网络程序所采用的通信协议(SOCKET_STREAM 表示创建 TCP 协议套接字,SOCK_DGRAM 表示创建 UDP 套接字,SOCK_RAW 表示创建原始套接字)
  • protocol : 由于指定了 type ,所以这里一般用 0 来代替就可以了
  • socket 函数成功时返回套接字描述符,失败时返回 -1

 

3.绑定函数 bind

int bind(int sockfd , struct sockaddr *my_addr , int addrlen)

  • sockfd : 由 socket调用 返回的套接字描述符
  • my_addr : 一个指向与协议对应的地址结构的指针。使用时需要讲指向特定协议地址结构的指针转换位指向 sockaddr 类型的指针。
  • addrlen  : sockaddr结构的长度
  • bind 函数成功时返回0,失败时返回-1

 

4.监听函数  listen

int listen(int sockfd,int backlog)

  • sockfd : 绑定后的套接字描述符
  • backlog : 设置请求排队的最大长度。当由多个客户端请求和服务器连接时,该参数表示可以接收的排队长度
  • listen函数调用成功返回0,失败返回-1

 

5.接受函数 accept

int accept(int sockfd , struct sockaddr *cliaddr , int *addrlen)

  • accept仅被 tcp 服务器调用。它从已完成连接的队列头返回下一个已完成的连接,若已完成连接的队列为空,则进入睡眠状态。
  • sockfd : 执行监听(listen)之后的套接字描述符。
  • client : 返回连接对方的套接字地址结构
  • addrlen : 返回对方套接字地址结构(client)的长度
  • accept 函数成功执行后会返回一个全新的描述符,代表与客户端的 tcp 连接。若失败则返回 -1

注意:监听套接字和已连接套接字是不同的两个概念。一个给定的服务器通常只会生成一个监听套接字并且一直存在,直到该服务器关闭。内核会为每个被接受的客户连接创建一个已连接套接字,当服务器完成某个客户的服务时,关闭该已连接套接字。监听描述符负责接收客户的连接请求,而已连接描述符负责与对应的客户进行数据传输。

 

6.连接函数 connect

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

  • tcp 客户端通过 connect 函数来建立一个与 tcp 服务器的连接
  • sockfd : 套接字描述符
  • serv_addr : 指向服务器套接字地址结构的指针,套接字地址结构必须含有服务器的 ip 地址和端口号
  • addrlen : serv_addr的长度

 

7.连接中止函数close

int close(int sockfd)  关闭套接字

 

下面是完整的 服务端 代码:

 1   #include<stdio.h>
 2   #include<stdlib.h>
 3   #include<errno.h>
 4   #include<string.h>
 5   #include<netinet/in.h>
 6   #include<arpa/inet.h>
 7   #include<unistd.h>
 8   
 9   int main()
10   {
11   /*定义套接字描述符,客户和服务器的套接字地址变量*/
12      int sockfd , new_fd; //定义监听套接字和已连接套接字
13      struct sockaddr_in server; //服务端地址和其他信息
14      struct sockaddr_in client; //客户端地址和其他信息
15      int sin_size , port = 5050; //定义端口号
16      
17      /*服务器端开始建立 socket 描述符*/
18      if((sockfd = socket(AF_INET , SOCK_STREAM , 0))==-1)
19      {
20          printf("Socket error : %s\n",strerror(errno));
21          exit(1);
22      }
23      /*设置地址重用选项。由于系统默认只允许一个套接字绑在一个特定的协议地址上,并且当套接字关闭后系统仍不允许在该地址上绑定其他套接字。*/
24      int opt = SO_REUSEADDR;
25      setsockopt(sockfd , SOL_SOCKET , SO_REUSEADDR , &opt , sizeof(opt));
26      /*套接字绑定特定地址和端口,进入监听状态*/
27      bzero(&server , sizeof(struct sockaddr_in)); //将字节字符串前 n 个字节置0
28      server.sin_family = AF_INET;
29      server.sin_addr.s_addr = htonl(INADDR_ANY);
30      server_addr.sin_port = htons(port); //填充套接字地址结构,包括地址族,ip和端口号
31      /*sockfd 绑定到套接字地址*/
32      if(bind(sockfd , (struct sockaddr *)(&server) , sizeof(struct sockaddr))==-1)
33      {
34          printf("Bind error : %s\n",strerror(errno));
35          exit(1);
36      }
37      /*sockfd 进入监听状态*/
38      if(listen(sockfd , 1)==-1)
39      {
40          printf("Listen error : %s\n",strerror(errno));
41          exit(1);
42      }
43      sin_size = sizeof(struct sockaddr_in);
44      /*接收连接请求*/
45      if((new_fd = accept(sockfd , (struct sockaddr *)(&client) , &sin_size))==-1)
46      {
47          printf("Accept error"%s\n",strerror(errno));
48          exit(1);
49      }
50     printf("You got a connection from client's ip is %s , port is %d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
51 
52      /*传输数据*/
53      if(write(new_fd , "hello" , strlen("hello"))==-1)
54      {
55          printf("Write error : %s\n",strerror(errno));
56          exit(1);
57      }
58      /*关闭套接字*/
59      close(new_fd);
60      close(sockfd);
61   
62     return 0;
63 }

 

客户端代码:

  

 1   #include<stdio.h>
 2   #include<stdlib.h>
 3   #include<errno.h>
 4   #include<string.h>
 5   #include<netinet/in.h>
 6   #include<arpa/inet.h>
 7   #include<unistd.h>
 8   int main()
 9   {
10     int sockfd;
11    char buffer[1024];
12     struct sockaddr_in server;
13     int port = 5050 ,nbytes; //参见服务端代码
14     char *serverip = "127.0.0.1"; //设置服务器地址为本机
15      /*创建套接字*/
16      if((sockfd = socket(AF_INET , SOCK_STREAM , 0))==-1)
17      {
18          printf("Socket error:%s\n",strerror(errno));
19          exit(1);
20      }
21      /*连接服务器*/
22      bzero(&server , sizeof(struct sockaddr_in));
23      server.sin_family = AF_INET;
24      /*地址格式转换*/
25      if(inet_aton(serverip , &server_addr.sin_addr)==0)//转换字节序同时给 sin_addr 赋值服务端 ip
26      {
27          printf("The server IP is not right !\n");
28          exit(1);
29      }
30      server.sin_port = htons(port);
31      //填充服务端的套接字结构
32  
33      /*调用 connect 函数来连接到服务器*/
34      if((connect(sockfd , (struct sockaddr *)(&server) , sizeof(struct sockaddr)))==-1)
35      {
36          printf("Connect error:%s\n",strerror(errno));
37          exit(1);
38      }
39      nbytes = read(sockfd , buffer , 1024);
40    if(nbytes < 0)
41    {
42      printf("Read error:%s\n",strerror(errno));
43      exit(1);
44    }
45      close(sockfd);
46    printf("Received %d bytes :%s\n",nbytes , buffer);
47      return 0;
48  }

 

 stdio.h : 包含标准输入输出函数 printf()

 stdlib.h : 包含异常退出函数 exit()

 errno.h : 包含报告错误信息函数 strerror(errno)

 string.h : 包含字符串处理函数

 netinet/in.h : 包含多个与网络程序相关的函数和数据结构

 arpa/inet.h : 包含 write和close 函数

 unistd.h : inet_ntoa()函数

有关 tcp/ip 协议和 大字节序小字节序,大家可以自行百度,我在这里就不详细叙述了。

转载于:https://www.cnblogs.com/camel97/p/6763420.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值