Linux系统C语⾔sockettcp套接字编程
1.套接字的地址结构:
1 typedef uint32_t in_addr_t; //32位⽆符号整数,⽤于表⽰⽹络地址
2struct in_addr{
3 in_addr_t s_addr; //32位 ipv
4 地址
4 }
5 typedef uint16_t in_port_t; //16位⽆符号整数,⽤于表⽰端⼝号
6struct sockaddr_in{
7 uint8_t sin_len; //结构长度,8位⽆符号整数
8 sa_family_t sin_family; //套接字地址族
9 in_port_t sin_port; //16位 TCP 或 UDP 端⼝号
10struct in_addr sin_addr; //32位 ipv4 地址
11char sin_zero[8]; //暂时不⽤。总置为0
12 }
2.创建套接字函数 socket
int socket(int family , int type , int protocol)
printf输出格式linuxfamily : 说明⽹络程序采⽤的通信协议族(⽐如 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
9int main()
10 {
11/*定义套接字描述符,客户和服务器的套接字地址变量*/
12int sockfd , new_fd; //定义监听套接字和已连接套接字
13struct sockaddr_in server; //服务端地址和其他信息
14struct sockaddr_in client; //客户端地址和其他信息
15int sin_size , port = 5050; //定义端⼝号
16
17/*服务器端开始建⽴ socket 描述符*/
18if((sockfd = socket(AF_INET , SOCK_STREAM , 0))==-1)
19 {
20 printf("Socket error : %s\n",strerror(errno));
21 exit(1);
22 }
23/*设置地址重⽤选项。由于系统默认只允许⼀个套接字绑在⼀个特定的协议地址上,并且当套接字关闭后系统仍不允许在该地址上绑定其他套接字。*/ 24int 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 绑定到套接字地址*/
32if(bind(sockfd , (struct sockaddr *)(&server) , sizeof(struct sockaddr))==-1)
33 {
34 printf("Bind error : %s\n",strerror(errno));
35 exit(1);
36 }
37/*sockfd 进⼊监听状态*/
38if(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/*接收连接请求*/
45if((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/*传输数据*/
53if(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
62return0;
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>
8int main()
9 {
10int sockfd;
11 char buffer[1024];
12struct sockaddr_in server;
13int port = 5050 ,nbytes; //参见服务端代码
14char *serverip = "127.0.0.1"; //设置服务器地址为本机
15/*创建套接字*/
16if((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/*地址格式转换*/
25if(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 函数来连接到服务器*/
34if((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);
47return0;
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 协议和⼤字节序⼩字节序,⼤家可以⾃⾏百度,我在这⾥就不详细叙述了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论