Linux下TCP/IP|Linux下TCP/IP socket编程(C++)

一、基于TCP的c/s交互流程 Linux下TCP/IP|Linux下TCP/IP socket编程(C++)
文章图片
C/S
Linux下TCP/IP|Linux下TCP/IP socket编程(C++)
文章图片
C/S

  • 【Linux下TCP/IP|Linux下TCP/IP socket编程(C++)】服务器端:
    socket() → bind() → listen() → accept() → recv()/read() ? send()/write() → close()
    创建socket → 绑定socket和端口号 → 监听端口号 → 接收来自客户端的连接请求 → 从socket中读取字符 → 关闭socket
  • 客户端:
    socket() → connect() → send()/write() ? recv()/read() → close()
    创建socket → 连接指定服务器的IP/端口号 → 向socket中写入信息 → 关闭socket
二、C++代码实现 1、server.cpp 按照该实现,服务器每次只能服务一个客户端。
#include #include #include #include #include #include #include #include #include #include "cs.h" #include "ErrCode.h"using namespace std; #define PORT 9977 #define MSG_SIZE 4096 #define MAX_LINE 20int server() { char cMsg[MSG_SIZE], sMsg[MSG_SIZE]; struct sockaddr_in serverAddr; // 一个将来与套接字绑定的结构体 memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_port = (PORT); // 从服务器的PORT端口接收客户端信息 serverAddr.sin_family = AF_INET; // 协议簇,AF_INET表示TCP/IP协议 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 指定接收的信息来自于某个IP,这里随意int fd_skt = socket(AF_INET, SOCK_STREAM, 0); // (1)socket函数新建套接字fd_skt if (fd_skt < 0) { perror("server socket err"); return SERVER_SOCKET_ERR; }if (bind(fd_skt, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0 ) { // (2)bind绑定套接字与serverAddr perror("server bind err"); return SERVER_BIND_ERR; } if (listen(fd_skt, MAX_LINE) < 0) { // (3)listen监听套接字fd_skt perror("server listen err"); return SERVER_LISTEN_ERR; } cout << "Listening..." << endl; while(1) { memset(cMsg, 0, sizeof(cMsg)); memset(sMsg, 0, sizeof(sMsg)); struct sockaddr_in clientAddr; socklen_t length = sizeof(clientAddr); int fd_client = accept(fd_skt, (struct sockaddr*)&clientAddr, &length); // (4)accept接收连接请求:程序在此阻塞直至产生第一次握手 // 接收到的信息存于第二第三个参数中 // 返回值是新的文件描述符,用于后续read和write调用if (fd_client < 0) { perror("server accept err"); return SERVER_ACCEPT_ERR; }cout << "server: got connection from " << clientAddr.sin_addr.s_addr << ", port " << PORT << ", socket" << fd_client << endl; while(1) { int cLen = recv(fd_client, cMsg, sizeof(cMsg), 0); // (5)read将接收到的客户端消息存在cMsg中 if (cLen <= 0) { perror("server recv err"); return SERVER_RECV_ERR; } cMsg[cLen] = '\0'; cout << "Receive message form <" << clientAddr.sin_addr.s_addr << ">: " << cMsg << endl; cin.ignore(1024,'\n'); // 去除上一个cin残留在缓冲区的\n cin.getline(sMsg, sizeof(sMsg)); // 不用cin,因为不能含空格 if(strcmp(sMsg, "quit\n") == 0){ break; // 结束对当前客户端的服务 }if(send(fd_client, sMsg, strlen(sMsg), 0) <= 0) { // (6)send将服务器的消息发给客户端 perror("server send err"); return SERVER_SEND_ERR; } // recv和send的返回值: // >0表示成功,返回实际发送或接受的字节数 // =0表示超时,对方主动关闭了连接过程 // <0出错 cout << "Send message to <" << clientAddr.sin_addr.s_addr << ">: " << sMsg << endl; } close(fd_client); cout << "当前客户端已结束通信,是否继续等待其他客户端?(1 - 是, 0 - 否)" << endl; bool isContinue = false; cin >> isContinue; if (!isContinue) { break; } } close(fd_skt); return SUCCESS; }

2、client.cpp
#include #include #include #include #include #include #include #include #include #include "cs.h" #include "ErrCode.h"using namespace std; #define PORT 9977 #define MAX_LINE 20 #define MSG_SIZE 4096 #define DEFAULT_SERVER "127.0.0.1"int client() { char cMsg[MSG_SIZE], sMsg[MSG_SIZE]; struct sockaddr_in serverAddr; // 一个将来与套接字绑定的结构体 memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_port = (PORT); // 从客户端的PORT端口接收服务器信息 serverAddr.sin_family = AF_INET; // 协议簇,AF_INET表示TCP/IP协议 cout << "Please input the server address: (输入1连接默认服务器)" << endl; char sAddr[20]; cin >> sAddr; if (strcmp(sAddr, "1") == 0) { if(inet_pton(AF_INET, DEFAULT_SERVER, (void *)&serverAddr.sin_addr) <= 0) { perror("client inet_pton err"); return CLIENT_INETPTON_ERR; } } else { if(inet_pton(AF_INET, DEFAULT_SERVER, (void *)&serverAddr.sin_addr) <= 0) { perror("client inet_pton err"); return CLIENT_INETPTON_ERR; } }int fd_skt = socket(AF_INET, SOCK_STREAM, 0); // (1)socket函数新建套接字fd_skt if (fd_skt < 0) { perror("client socket err"); return CLIENT_SOCKET_ERR; }if (connect(fd_skt, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { //(2)connect向服务器发起连接请求 perror("client connect err"); return CLIENT_CONNECT_ERR; }cout << "Connect Success! \nBegin to chat..." << endl; while(1) { memset(cMsg, 0, sizeof(cMsg)); memset(sMsg, 0, sizeof(sMsg)); cin.ignore(1024,'\n'); // 去除上一个cin残留在缓冲区的\n cin.getline(cMsg, sizeof(cMsg)); // 不用cin,因为不能含空格 if(strcmp(cMsg, "quit\n") == 0){ break; } if(send(fd_skt, cMsg, strlen(cMsg), 0) < 0) { // (3)send,客户端向服务端发消息 perror("client send err"); return CLIENT_SEND_ERR; } cout << "Send message to <" << serverAddr.sin_addr.s_addr << ">: " << cMsg << endl; int sLen = recv(fd_skt, sMsg, sizeof(sMsg),0); // (4) recv,接收服务器发来的消息 if(sLen <= 0) { perror("client recv err"); return CLIENT_RECV_ERR; } sMsg[sLen] = '\0'; cout << "Receive message form <" << serverAddr.sin_addr.s_addr << ">: " << sMsg << endl; } close(fd_skt); }

3、main.cpp
#include #include "cs.h"using namespace std; int main() { cout << "————————【chat start】————————" << endl; while(1) { cout << "Client or Server?" << endl; char cs; cin >> cs; if (cs == 's') { if(server() != 0){ break; } } else if (cs == 'c') { if(client() != 0){ break; } } else { cout << "err input" << endl; } } cout << "————————【chat end】————————" << endl; return 0; }

4、ErrCode.h
#define SUCCESS0#define SERVER_SOCKET_ERR1000 #define SERVER_BIND_ERR1001 #define SERVER_LISTEN_ERR1002 #define SERVER_ACCEPT_ERR1003 #define SERVER_RECV_ERR1004 #define SERVER_SEND_ERR1005#define CLIENT_INETPTON_ERR 1010 #define CLIENT_SOCKET_ERR1011 #define CLIENT_CONNECT_ERR1012 #define CLIENT_SEND_ERR1013 #define CLIENT_RECV_ERR1014

5、cs.h
#include int server(); int client();

3、运行效果 Linux下TCP/IP|Linux下TCP/IP socket编程(C++)
文章图片
client Linux下TCP/IP|Linux下TCP/IP socket编程(C++)
文章图片
server

    推荐阅读