赞
踩
大家好,我是练习编程时长两年半的个人练习生昆工第一ikun,今天我们来分享TCP通信模型,并且用C语言实现它。
目录
(2)套接字绑定 -->bind() 核心:IP地址与PORT端口
1.客户端给服务器发送一个字符串,服务器返回给客户端这个字符串的长度。
2.实现一个时间服务器,客户端发送time,服务器返回当前时间。
3.如果客户端发送get 1.txt的请求,服务器获取文件内容后,发送给客户端。
#include <sys/types.h> #include <sys/socket.h> int socket(int family, int type, int protocol); 参数: family:协议族 AF_INET:IPv4协议 AF_INET6:IPv6协议 AF_LOCAL:UNIX域协议 AF_ROUTE:路由套接字 AF_KEY:密钥套接字 type:套接字类型 SOCK_STREAM:流式套接字 SOCK_DGRAM:数据报套接字 SOCK_RAM:原始套接字 protocol:0(原始套接字除外) 返回值: 成功返回非负套接字描述符 失败返回-1;
端口:标识进程 无符号短整型: 0 ~ 65535 0 ~ 1024 被内核使用. 用户可指定端口:1025 ~ 65535
字节序:大端序 与 小端序 网络字节序通常是大端序: 大端就是指低地址存放高字节 个人PC的字节序通常是小端序: 小段就是指低地址存放低字节 结论:需要在网络绑定port端口时进行字节序的转换.....
字节序转换函数:htons、htonl 等....
可以使用man手册直接查看:man 3 htons h: 主机host to: 转换 n: net网络 s: short类型 htons就是把主机字节序转为网络字节序.
IP地址:标识主机 ipv4占四个字节.
点分十进制:"192.168.2.2" 是给人类看的 二进制形式:11000000 10101000 00000010 00000010 是计算机使用的
IP地址转换函数
点分转为二进制: in_addr_t inet_addr(const char *cp); cp: ip地址的字符串形式 in_addr_t: 转换后的二进制地址形式
#include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 参数: sockfd:套接字描述符 my_addr:绑定的地址 addrlen:地址长度 返回值: 成功返回0; 失败返回-1;
#include <sys/types.h> #include <sys/socket.h> int listen(int sockfd, int backlog); 参数: sockfd:套接字描述符 backlog:请求队列中允许的最大请求数,大多数系统默认值为5; 返回值: 成功返回0;失败返回-1;
注意:后续的数据通信全部使用通信套接字,不能使用监听套接字来通信
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 参数: sockfd:套接字描述符 addr:用于保护客户端地址,如果不需要客户端信息则传递 NULL addrlen:地址长度,如果不需要客户端信息则传递 NULL 返回值: 成功返回用于通信的套接字(连接套接字 或 通信套接字) 失败返回-1;
我们先来创建一个服务器:
- #include <strings.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <time.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <pthread.h>
-
- void *send_data(void *arg)
- {
- int connfd = *(int*)arg;
- char s[64] = {0};
- while(1)
- {
- fgets(s, 64, stdin);
- s[strlen(s)-1] = '\0';
- write(connfd, s, 64);
- memset(s, 0, 64);
- }
-
- }
-
- int main(int argc, char *argv[])
- {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sockfd == -1)
- {
- perror("socket");
- return -1;
- }
-
- //端口复用函数
- int on = 1;
- int k = setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, &on, sizeof(on));
- if(k == -1)
- {
- perror("setsockopt");
- return -1;
- }
-
-
- struct sockaddr_in ser;
- ser.sin_family = AF_INET;
- ser.sin_port = htons(11111);
- ser.sin_addr.s_addr = inet_addr("0.0.0.0");
-
- int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
- if(ret == 0)
- {
- printf("绑定成功\n");
- }
- else
- {
- perror("bind");
- return -1;
- }
-
- ret = listen(sockfd, 5);
- if(ret == 0)
- {
- printf("监听成功\n");
- }
- else
- {
- perror("listen");
- return -1;
- }
-
- struct sockaddr_in client;
- int n = sizeof(client);
-
- int connfd;
- while(1)
- {
- connfd = accept(sockfd, (struct sockaddr *)&client, &n);
- if(connfd == -1)
- {
- perror("accept");
- return -1;
- }
- else
- {
- printf("连接成功\n");
- }
-
- printf("client ip:%s\nclient port:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
-
- pthread_t pid;
- pthread_create(&pid, NULL, send_data, (void *)&connfd);
- pthread_detach(pid);
-
-
-
- while(1)
- {
- char buf[64] = {0};
- ret = read(connfd, buf, 64);
- if(ret < 0)
- {
- perror("read");
- return -1;
- }
- else if(ret == 0)
- {
- close(connfd);
- break;
- }
- printf(">>:%s\n", buf);
-
-
- if(strcmp(buf, "time") == 0)
- {
-
- time_t now = time(NULL);
- char *p = ctime(&now);
- char data[64];
- strcpy(data, p);
- write(connfd, data, strlen(data));
-
- memset(buf, 0, 64);
- memset(data, 0, 64);
- }
-
- else if(strncmp(buf, "get", 3) == 0)
- {
-
- int i, j = 0;
- char str[64] = {0};
- for(i = 4; i <= strlen(buf)-1; i++)
- {
- str[j] = buf[i];
- j++;
- }
- memset(buf, 0, 64);
- int fd = open(str, O_RDONLY);
- while((ret = read(fd, buf, 64)) != 0)
- {
- write(connfd, buf, ret);
- memset(buf, 0, 64);
- }
-
- write(connfd, "over", 64);
- memset(buf, 0, 64);
- memset(str, 0, 64);
- close(fd);
- }
- else
- {
- char arr[64];
-
- sprintf(arr, "%ld", strlen(buf));
- write(connfd, arr, strlen(arr));
- memset(buf, 0, 64);
- memset(arr, 0, 64);
-
- }
-
- }
- }
-
- close(sockfd);
-
-
- return 0;
- }
再来创建一个客户端:
- #include <strings.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/ip.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <pthread.h>
-
- void *recv_data(void *arg)
- {
- int sockfd = *(int *)arg;
- char s[64] = {0};
- while(1)
- {
- int ret = read(sockfd, s, 64);
- if(ret < 0)
- {
- perror("read");
- return NULL;
- }
- printf("%s\n", s);
- memset(s, 0, 64);
- }
-
- }
- int main(int argc, char *argv[])
- {
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(sockfd == -1)
- {
- perror("socket");
- return -1;
- }
-
- pthread_t pid;
- pthread_create(&pid, NULL, recv_data, (void *)&sockfd);
- pthread_detach(pid);
-
- struct sockaddr_in ser;
- ser.sin_family = AF_INET;
- ser.sin_port = htons(11111);
- //ser.sin_addr.s_addr = inet_addr("0.0.0.0");
- ser.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
- int ret = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser));
- if(ret == -1)
- {
- perror("connect");
- return -1;
- }
-
- char buf[64];
- while(1)
- {
- fgets(buf, 64, stdin);
- buf[strlen(buf)-1] = '\0';
- write(sockfd, buf, 64);
-
- if(strcmp(buf, "time") == 0)
- {
- char data[64];
- read(sockfd, data, 64);
- printf(">>:%s\n", data);
- memset(buf, 0, 64);
- memset(data, 0, 64);
- }
- else if(strncmp(buf, "get", 3) == 0)
- {
- char str[64];
- while(read(sockfd, str, 64) != 0)
- {
- if(strcmp(str, "over") == 0)
- {
- memset(str, 0, 64);
- break;
- }
- printf(">>:%s\n", str);
- memset(buf, 0, 64);
- memset(str, 0, 64);
- }
- }
- else
- { char arr[64] = {0};
- read(sockfd, arr, 64);
- printf(">>:%s\n", arr);
- memset(buf, 0, 64);
- memset(arr, 0, 64);
- }
- }
- close(sockfd);
-
- return 0;
- }
运行结果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。