本帖最后由 ぉ沙皮狗的忧伤 于 2021-3-10 10:22 编辑
TCP头格式
三次握手,四次挥手
S:连接性SYN=1,发起一个连接请求,调用connect()
A:应答位ACK=1,ack确定有效
F:断开位FIN=1,发送一个断开请求数据包,调用close
一、sever端代码编写
1、代码流程
①、socket建立流失套接字
②、signal改变该进程处理信号的方式
③、sockaddr_in成员初始化
④、bind绑定
⑤、listen设置为监听:被动连接
⑥、while循环,父进程等待连接,子进程处理已连接的客户端
2、添加头文件
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <strings.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
- #include <netinet/in.h>
- #include <netinet/ip.h>
-
- #include <signal.h>
- #include <arpa/inet.h>
复制代码
编写main函数,TCP并发服务器:采用多进程
3、建立流失套接字
- //建立流失套接字
- //参数1----地址族,AF_INET网络协议族
- //参数2----套接字类型,SOCK_STREAM使用TCP
- //参数3----protocol参数通常设置0
- //返回值---成功socket ID,出错返回-1
- serfd = socket( AF_INET, SOCK_STREAM, 0);
- if(serfd < 0){
- perror("socket failed!\n");
- exit(1);
- }
复制代码
4、设备该进程的信号处理方式
- //忽略SIGCHLD信号的处理,内核自动回收8kb物理资源
- //子进程结束会发送一个SIGCHLD信号给内核
- //参数1-----要处理的信号
- //参数2-----处理的方式,SIG_IGN屏蔽该信号
- signal( SIGCHLD, SIG_IGN);
复制代码
5、绑定本地IP地址和指定接收数据端口,通过bind绑定套接字和端口
- struct sockaddr_in self;
- bzero( &self, sizeof(self));
-
- self.sin_family = AF_INET; //选择ipv4协议
- self.sin_port = htons(6666); //选择端口
- self.sin_addr.s_addr = htonl(INADDR_ANY); //内核自动绑定
-
- ret = bind( serfd, (struct sockaddr *)&self, sizeof(self));
- if( ret < 0){
- perror("bind failed!\n");
- exit(1);
- }
复制代码
6、设置为监听模式,被动连接
- //参数1----被监听的套接字
- //参数2----指定正在等待的最大队列长度
- //返回值0或-1
- ret = listen(serfd, 5);
- if(ret < 0){
- perror("listen failed!\n");
- exit(1);
- }
复制代码
7、使用一个while循环,父进程等待连接,子进程处理客户端数据
- while(1){
-
- printf("wait client!\n");
- //5、父进程等待连接
- newfd = accept( serfd, (struct sockaddr *)&cli, &len);
- if(newfd < 0){
- perror("accept failed!\n");
- exit(1);
- }
-
- printf("new client ip = %s port = %d ok\n", inet_ntoa(cli.sin_addr),\
- ntohs(cli.sin_port));
-
- //6、创建一个子进程
- pid_t pid = fork();
- if(pid < 0){
- perror("fork failed!\n");
- exit(1);
- }
-
- if(pid > 0)
- continue;
-
- //子进程执行代码块
- if(pid == 0){
- //处理已连接客户端数据
- char buf[128];
- int ret = -1;
-
- while(1){
- bzero( buf, 128);
- ret = read( newfd, buf, 127);
- if(ret < 0){
- perror("read");
- exit(1);
- }
-
- //如果客户端输入quit或者Cttl+C关闭,服务器也会关闭
- if(!strncmp( buf, "quit", 4) || (buf[0] == 0)){
- close(newfd);
- break;
- }
-
- printf("ip = %s port = %d buf = %s\n", inet_ntoa(cli.sin_addr),\
- ntohs(cli.sin_port), buf);
-
- }
- exit(1); //结束当前进程
- }
- }
-
复制代码
二、client端代码编写1、添加头文件
- #include <string.h>
- #include <strings.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
- #include <netinet/in.h>
- #include <netinet/ip.h>
-
-
- #include <arpa/inet.h>
复制代码
2,创建流失套接字
- //创建流失套接字
- //参数1----地址族,AF_INET网络协议族
- //参数2----套接字类型,SOCK_STREAM使用tcp
- //参数3----protocol通常设置为0
- //返回值---成功socket id 失败 -1
- clifd = socket( AF_INET, SOCK_STREAM, 0);
- if(clifd < 0){
- perror("socket failed!\n");
- exit(1);
- }
复制代码
3、主动连接服务器:指定服务器IP和接收端口
- //主动连接服务器:指定服务器IP和接收端口
- struct sockaddr_in ser;
- bzero( &ser, sizeof(ser));
-
- ser.sin_family = AF_INET; //AF_INET网络协议族
- ser.sin_port = htons(6666); //要连接的服务器端口
- ser.sin_addr.s_addr = inet_addr("172.18.12.163"); //服务器ip
-
- ret = connect( clifd, (struct sockaddr *)&ser, sizeof(ser));
- if(ret < 0){
- perror("connect failed!\n");
- exit(1);
- }
复制代码
4、发送数据,从标准输入获取键盘的值
- while(1){
- fprintf( stderr, "input:");
- bzero( buf, 128);
- //从标准输入获取字符串
- fgets( buf, 127, stdin);
-
- //写入套接字中
- ret = write( clifd, buf, strlen(buf));
- if(ret < 0){
- perror("write failed!\n");
- exit(1);
- }
-
- if(!strncmp( buf, "quit", 4)){
- break;
- }
-
- }
复制代码
三、使用gcc编译sever端代码,在虚拟机上运行,使用交叉编译工具编译client端代码,在板卡上运行
四、运行可执行程序
代码在附件中。。。。
|