赞
踩
socket套接字的有些知识在上一篇【UDP】socket套接字带你快速上手中已经讲过了,这里就不在过多的叙述了。
TCP的主要特点
- TCP是面向连接的传输层协议
- TCP提供可靠交付的服务
- TCP提供全双工通信
- TCP是面向字节流的
- 此函数是用来创建socket文件描述符的。创建成功则返回socket文件描述符,失败则返回-1并且设置对应的错误码
- 第一个参数是用来指定通信域的,也就是选择用于通信的协议族的,这里用的是IPv4协议,参数指定就是AF_INET
- 第二个参数是用来指定通信类型的。这里所用到的是TCP,所以参数指定为SOCK_STREAM,表示面向流的传输协议
- 第三个参数暂时用不到,设置为0即可
- 此函数是用来将用户设置的IP地址和port端口号在内核中和当前进程强关联。成功返回0,失败返回-1并且设置对应的错误码
- 第一个参数是你创建好的socket文件描述符
- 第二个参数是一个struct sockaddr的结构体指针
- 第三个参数是这个sockaddr的大小
- 此函数用来声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略
- listen成功返回0,失败返回-1并且设置对应的错误码
- 三次握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到客户端连接上来
- 第一个参数是创建好的socket文件描述符
第二个参数是一个struct sockaddr的结构体指针
第三个参数是此结构体的大小
返回值为socket文件描述符
理解accept的返回值
accept中传入了一个socket文件描述符,但是它返回的依然是一个文件描述符,那么如何理解这两个文件描述符呢?
举个例子,假如你家有个饭店,刚好这时到了饭点了,你就派出了张三到饭店门口去拉客,此时来了一名顾客正好被张三拉进到店里去了,你又派出了李四服务员去服务这位顾客,并且让张三又返回到店门口继续拉客。
在上述例子中,张三就是我们传入accept中的socket文件描述符,是获取到的新连接的,而李四就是accept返回的socket文件描述符,是真正提供服务的。
- 在客户端中调用,用来连接服务器
- 参数形式和bind的一致,区别在于bind传入的是自己的地址,为connect传入的是对方的地址
- listen成功返回0,失败返回-1并且设置对应的错误码
- #include <iostream>
- #include <string>
- #include <cstring>
- #include <cstdio>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
-
- void Usage(std::string proc)
- {
- std::cout << "\nUsage: " << proc << " serverIp serverPort\n"
- << std::endl;
- }
-
- int main(int argc, char *argv[])
- {
- if (argc != 3)
- {
- Usage(argv[0]);
- exit(1);
- }
- std::string serverip = argv[1];
- uint16_t serverport = atoi(argv[2]);
-
- bool alive = false;
- int sock = 0;
- std::string line;
- while (true)
- {
- if (!alive)
- {
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- {
- std::cerr << "socket error" << std::endl;
- exit(2);
- }
- struct sockaddr_in server;
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_INET;
- server.sin_port = htons(serverport);
- server.sin_addr.s_addr = inet_addr(serverip.c_str());
-
- if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0)
- {
- std::cerr << "connect error" << std::endl;
- exit(3);
- }
- alive = true;
- std::cout << "connect success" << std::endl;
- }
- std::cout << "请输入你的内容# ";
- std::getline(std::cin, line);
- if (line == "quit")
- break;
-
- ssize_t s = send(sock, line.c_str(), line.size(), 0);
- if (s > 0)
- {
- char buffer[1024];
- ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
- if (s > 0)
- {
- buffer[s] = 0;
- std::cout << "server 回应# " << buffer << std::endl;
- }
- else if (s == 0)
- {
- close(sock);
- }
- }
- else
- {
- close(sock);
- }
- alive = false;
- }
-
- return 0;
- }
- #include "tcp_server.hpp"
- #include <memory>
-
- static void Usage(std::string proc)
- {
- std::cout << "\nUsage" << proc << " port\n" << std::endl;
- }
-
- int main(int argc, char* argv[])
- {
- if(argc != 2)
- {
- Usage(argv[0]);
- exit(1);
- }
- uint16_t port = atoi(argv[1]);
- std::unique_ptr<Tcp_Server> svr(new Tcp_Server(port));
- svr->InitServer();
- svr->Start();
- return 0;
- }
- #pragma once
-
- #include <iostream>
- #include <string>
- #include <cstring>
- #include <strings.h>
- #include <assert.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <pthread.h>
- #include <sys/wait.h>
- #include "log.hpp"
-
- static void service(int sock, const std::string &clientip, const uint16_t &clientport)
- {
- char buffer[1024];
- while (true)
- {
- ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
- if (s > 0)
- {
- buffer[s] = 0;
- std::cout << clientip << ":" << clientport << "# " << buffer << std::endl;
- }
- else if (s == 0) // 对端关闭连接
- {
- logMessage(NORMAL, "%s:%d shutdown, me too", clientip.c_str(), clientport);
- break;
- }
- else
- {
- logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
- break;
- }
-
- write(sock, buffer, strlen(buffer));
- }
- close(sock);
- }
-
- class ThreadDate
- {
- public:
- int _sock;
- std::string _ip;
- uint16_t _port;
- };
-
- class Tcp_Server
- {
- private:
- const static int gbacklog = 20;
- static void *threadRoutine(void *args)//必须得是static,因为不是static的话会多出一个this指针
- {
- pthread_detach(pthread_self());//线程分离
- ThreadDate *td = static_cast<ThreadDate*> (args);
- service(td->_sock, td->_ip, td->_port);
- delete td;
-
- return nullptr;
- }
-
- public:
- Tcp_Server(uint16_t port, std::string ip = "")
- : _port(port), _ip(ip), listensock(-1)
- {
- }
- ~Tcp_Server()
- {
- }
-
- void InitServer()
- {
- // 1.创建socket
- listensock = socket(AF_INET, SOCK_STREAM, 0);
- if (listensock < 0)
- {
- //创建socket失败
- logMessage(FATAL, "create socket error, %d:%S", errno, strerror(errno));
- exit(2);
- }
- logMessage(NORMAL, "create socket success, listensock:%d", listensock);
-
- // 2.bind
- struct sockaddr_in local;
- memset(&local, 0, sizeof local);
- local.sin_family = AF_INET;
- local.sin_port = htons(_port);
- local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str()); //INADDR_ANY:任意IP
- if (bind(listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
- {
- //bind失败
- logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
- exit(3);
- }
-
- // 3.建立连接
- if (listen(listensock, gbacklog) < 0)
- {
- //建立连接失败
- logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
- exit(4);
- }
-
- logMessage(NORMAL, "init server success");
- }
-
- void Start()
- {
- // signal(SIGCHLD, SIG_IGN);//多进程版
- while (true)
- {
- // 4.获取连接
- struct sockaddr_in src;
- socklen_t len = sizeof(src);
- int servicesock = accept(listensock, (struct sockaddr *)&src, &len);
- // 获取连接失败
- if (servicesock < 0)
- {
- logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
- continue;
- }
- // 获取连接成功
- uint16_t client_port = ntohs(src.sin_port);
- std::string client_ip = inet_ntoa(src.sin_addr);
- logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n", servicesock, client_ip.c_str(), client_port);
-
- // 5.开始通信
- // 版本1——单进程循环版
- // 缺点:一次只能处理一个客户端,处理完后才能处理下一个
- // service(servicesock, client_ip, client_port);
- // close(servicesock);
-
- //版本2.0——多进程(创建子进程)
- // pid_t id = fork();
- // assert(id != -1);
- // if(id == 0)
- // {
- //子进程
- // close(listensock);
- // service(servicesock, client_ip, client_port);
- // exit(0);
- // }
- //父进程
- // close(servicesock);
-
- //版本2.1——多进程版本(孤儿进程)
- // pid_t id = fork();
- // assert(id != -1);
- // if(id == 0)
- // {
- //子进程
- // close(listensock);
- // if(fork() > 0) exit(0);//子进程退出,由操作系统领养
- //孙子进程
- // service(servicesock, client_ip, client_port);
- // exit(0);
- // }
- //父进程
- // waitpid(id, nullptr, 0);
- // close(servicesock);
-
- //版本3——多线程版
- ThreadDate *td = new ThreadDate();
- td->_sock = servicesock;
- td->_ip = client_ip;
- td->_port = client_port;
- pthread_t tid;
- pthread_create(&tid, nullptr, threadRoutine, td);
- }
- }
-
- private:
- uint16_t _port;
- std::string _ip;
- int listensock;
- };
TCP socket:TCP Socket
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。