C++ MFC Socket communication ini configuration file reading + ASCLL code data transmission and segmentation to implement string split function

Introduction to ini files

The ini file is a file with the suffix ini. It can be the initialization configuration file of the project. That is to say, after the project is released, the information in the configuration file can be modified according to the needs without modifying the project source code. The following is an example of the ini file content of my project.

You can see that there is a title [ConnectionMessage] in this ini file. There are two fields under this title. The format is field name = field value, as shown in the figure above. There can be multiple titles in the same ini file, and there can be multiple fields under each title.

Two ini file reading

C++ reading ini file

/*

::GetPrivateProfileString(title to be read,
                          The field name in the title that needs to be read,
                          The value to populate if the field is not present in the header,
                          Put the obtained value into the buffer of the variable,
                          Buffer size (consistent with the buffer size of the previous parameter),
                          The path to the ini file (because it is in the project, you can use a relative path));
Read the data as a string, the parameter list is as above
In addition:: means that the global function is called instead of its own function in the class


The following is an example of reading data as an integer
::GetPrivateProfileInt(_T("ConnectionMessage"),
                       _T("PORT"),
                       -1, 
                       _T(".\Socket.ini"));
Parameter list: title, field name, if the set value is not read, file path
Return value: If found successfully, it is the value of the target field, if not found, it is the set value.

In addition, if you want to write an ini file, use the following function
BOOL WritePrivateProfileString(
      ini file title name
      Field name
      Field value (must be of CString or LPCTSTR type)
      ini file path
);


*/
CString SocketPort, ServerIP; //Declaration string
::GetPrivateProfileString(_T("ConnectionMessage"), _T("IP"), _T("Error"), ServerIP.GetBuffer(50), 50, _T(".\Socket.ini"));
::GetPrivateProfileString(_T("ConnectionMessage"), _T("PORT"), _T("Error"), SocketPort.GetBuffer(50), 50, _T(".\Socket.ini"));
//::GetPrivateProfileInt(_T("ConnectionMessage"), _T("PORT"),-1, _T(".\Socket.ini"));

CStringA s;
s = ServerIP.GetBuffer(0);
/*GetBuffer() provides a memory size that you can write to,
It means to apply for a piece of memory, but it is inside the CString object.
Re-modify the size of CString memory and modify the contents inside.
Parameter 0 means not to apply for memory and fill the content into the original CString object*/
serverIP = s.GetBuffer(0);
/*Note that I am case-sensitive, because I am S and s
In addition, why is it so troublesome? Can't CString be converted directly to string?
Because this is Unicode encoding, if it is multi-byte encoding, just string=CString.GetBuffer*/
s.ReleaseBuffer();//Note that after applying for resources, you must release them
s=SocketPort.GetBuffer(0);
serverPort = s.GetBuffer(0);
s.ReleaseBuffer();

C# reads ini file

The sample ini file is populated as follows

string stationPath = @".\example.ini";
/*Add @ before the string to force escaping
That is, \ is not regarded as an escape character but as a symbol. Line breaks within characters can also be accepted */
string res = "";
if (File.Exists(stationPath))
 {
  StreamReader sr = new StreamReader(stationPath, true); //Initialize a new instance for the specified file name with the mark detection option for the specified byte order
   while (sr.Peek() > 0) //Peek() returns the next available character but does not use it
   {
     res = sr.ReadLine().Trim();//Because there is only one line in our ini file, only read one line and remove the following spaces
   }
   sr.Close();//Remember to close the stream
}
   string ip=res.Split(';')[0];
   string username=res.Split(';')[1];
   string pwd=res.Split(';')[2];
///Continue processing later

Three C++ Socket Communication

Server

 example* Dlg = (example*)lpParamX;
//I wrote a thread for communication. At the same time, if you need a pop-up box, you need the main window handle. If you don't have a thread, you can ignore the previous sentence.
/*Define the sending and receiving length*/
int send_len = 0;
int recv_len = 0;
/*Define the send and receive buffer*/
char send_buf[200];
char recv_buf[200];
//define socket
SOCKET Socket,communicationSocket;
//Declare the connection information structure
SOCKADDR_IN server_addr;
/*Here SOCKADDR_IN SOCKADDR corresponds to sockaddr_in sockaddr respectively.
*/
try{
//Create socket
Socket = socket(AF_INET, SOCK_STREAM, 0);
if (Socket < 0)
{
Dlg->MessageBox(L"Failed to create socket");
return -1;
}
//Structure filling
const char *IP = serverIP.data();//string to char* can be converted using string.data
const char * portTemp = serverPort.data();
\t\t
int port = atoi(portTemp);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
\t\t
\t\t
int a=sizeof(server_addr);
\t\t
//bind(Socket, (SOCKADDR *) & amp;server_addr, sizeof(SOCKADDR_IN));

if (bind(Socket,(const struct sockaddr*) &server_addr,a)<0)
{
Dlg->MessageBox(L"Binding failed");
return -1;
}
if (listen(Socket, 1) < 0)
{
Dlg->MessageBox(L"Listening failed");
}
struct sockaddr_in clientaddr;
int sockLen = sizeof(struct sockaddr_in);
communicationSocket = accept(Socket,(SOCKADDR *) & amp;clientaddr, & amp;sockLen);
        while(true)
{

recv_len = recv(communicationSocket, recv_buf, 200, 0);
if (recv_len < 0)
{
continue;
}
else
{
recv_buf[recv_len] = '\0';
string s = recv_buf;
CString msg;
//msg.Format(L"Server information: %s",s.c_str());
//msg.Format(L"Server information:%s", CStringW(recv_buf));
//msg.Format(L"Server information:%s", CStringW(recv_buf[0]));
temp = Dlg->ascll2Int(recv_buf);//This is a function I wrote myself to split the ascll string
\t\t\t\t\t
\t\t\t\t\t
\t\t\t\t\t
ss = temp.c_str();
msg.Format(L"Client message:%s",ss);
                }
             }

Things that the server needs to pay attention to when writing Socket are as follows

1. To convert string to char*, you can use the string.data() method.

2 if(bind(Socket, (SOCKADDR *) &server_addr, sizeof(SOCKADDR_IN))<0); At first glance, there is no problem with this bind binding function, but when compiling, an error is reported, prompting that the value types on both sides of < do not match. After searching for a long time, I found that the overloading of the bind function is wrong. Although the parameters you wrote are all parameters of bind() whose return value is int, the compiler may think that you wrote another overloading. This can be placed with the mouse. Check the current bind function name to see if it is the overload we need. In order to ensure that the function overload we want is used correctly, we can declare a parameter type variable and then assign the value to the function. If we directly put the value in It may be wrong.

3 if(bind(Socket, (SOCKADDR *) & amp;server_addr, int **); The variable in the middle must be noted to have the & amp; symbol, otherwise it will prompt that the conversion cannot be performed

client

 Client structure filling code
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(IP);
server_addr.sin_port = htons(port);
        int recv_len;
\t\t//connect to the server
if (connect(Socket, (SOCKADDR *) & amp;server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
//Dlg->MessageBox(L"Socket connection to server failed", L"Prompt");
}
else
{
//Dlg->MessageBox(L"Connection to server successful", L"Prompt");
               recv_len = recv(communicationSocket, recv_buf, 200, 0);
if (recv_len < 0)
{
continue;
}
else//Send and receive operations
{
recv_buf[recv_len] = '\0';
string s = recv_buf;
CString msg;
//msg.Format(L"Server information: %s",s.c_str());
/*The format function cannot directly convert s.c_str() into the form of L"%s"
  You can declare a CString outside and then assign c_str();
  L"%s" in the format function can be filled with CStringW(char *)
*/
 //msg.Format(L"Server information:%s", CStringW(recv_buf));
//msg.Format(L"Server information:%s", CStringW(recv_buf[0]));
temp = Dlg->ascll2Int(recv_buf);
\t\t\t\t\t
//char tempChar = (char)temp[0];
\t\t\t\t\t
ss = temp.c_str();
msg.Format(L"Server information:%s",ss);
                   Dlg->messageBox(msg);
}
          }
\t\t
        

Four C++ ASCLL code string splitting manually implements split(char a[],char str);

Today I encountered a requirement when writing a project: the string passed in the Socket is composed of ASCLL characters.

Such as 66 55 50 51 57 48 48 54 49 44 49 52 46 48 48 48 44 50 55 50 51 46 48 48 48 44 50 53 48

B72390061,14.000,2723.000,250

The segmentation principle is as follows

//Convert the incoming ASCLL string into string, why string? Because I got it from Socket
string ascll2String(char *ascll)
{
char *p = ascll;
char tempAscllValue[50];//Determine the size yourself
int j = 0;
for (j = 0; j < 50; j + + )
{
tempAscllValue[j] = '\0';//Initialization
}
int i = 0, temp;
while (*p != '\0' & amp; & amp;i < 50)
{
if (*p == ' ')//There are spaces in the character array passed in, move it
p + + ;
temp = (*p - 48) * 10;
p + + ;
temp = temp + (*p) - 48;//Take two characters to spell the ASCLL code
//tempAscllValue[i] = *p * 10 + *( + + p);
tempAscllValue[i] = char(temp);//Convert the spelled ASCLL into the corresponding symbol
p + + ;
i + + ;
}
\t
string s = tempAscllValue;

}
//Split the string according to
char piHao[20], guiGe[10], theroCount[5], theroWeight[10],realWeight[10];
int i = 0,j=0,k=0,p=0,q=0,ii=0;
int dataType = 0;//0-plan number 1-specification 2-theoretical weight 3-theoretical count 4-actual weight
while (i < temp.length()) //Fill the array
{
if (temp[i] == ',')
    {
\t\t\t\t\t\t
if (dataType == 0)
ii = i;
i + + ;
dataType + + ;
\t\t\t\t\t\t
continue;

}
if (dataType == 0)
{
piHao[i] = temp[i];

}
else if (dataType == 1)
{
guiGe[j] = temp[i];
j + + ;
}
else if (dataType == 2)
{
theroWeight[k] = temp[i];
k++;
}
else if (dataType == 3)
{
theroCount[p] = temp[i];
p + + ;
}
else if (dataType == 4)
{
realWeight[q] = temp[i];
q + + ;
}
i + + ;
}
//seal
guiGe[j] = '\0';
theroCount[p] = '\0';
theroWeight[k] = '\0';
realWeight[q] = '\0';
piHao[ii] = '\0';

Split the implementation and test code. Note: VS does not support the use of arr[size + 1], so I used pointers.

codeBlocks can use the above writing method, but it is not recommended to write

#include <iostream>
#include<vector>
using namespace std;
void split(string s, char str, vector<string> & amp; stringVector);
int main()
{
    string s1 = "123;456;789;11";
    cout << "s1 len=" << s1.length() << endl;
    string s2 = ";123;456;123";
    string s3 = ";123,456;789;;";
    string s4 = "1:2,3,456;789;;";
    vector<string> res1, res2, res3;
    cout << "start" << endl;
    split(s1, ';', res1);
    split(s2, ';', res2);
    split(s3, ';', res3);
    int i = 0;
    cout << "******************res1******************" << endl;
    while (i < res1.size())
    {
        cout << "Split number" << i << "number:" << res1[i] << endl;
        i + + ;
    }
    i = 0;
    cout << "******************res2************************" << endl;
    while (i < res2.size())
    {
        cout << "Split number" << i << "number:" << res2[i] << endl;

        i + + ;
    }
    i = 0;
    cout << "******************res3**********************" << endl;
    while (i < res3.size())
    {
        cout << "Split number" << i << "number:" << res3[i] << endl;
        i + + ;
    }
    return 0;
}
//String string to be split, target character, storage location after splitting
void split(string s, char str, vector<string> & amp; stringVector)

{
    int i = 0;
    char* start = &s[0];
    char* endStr = &s[0];
    while (i < s.length())
    {
        if (s[i] == str)
        {
            int size = endStr - start;
            char *arr =new char[size + 1];
            int j = 0;
            while (start != endStr)//At this time endStr==str so it is !=
            {
                arr[j] = *start;
                j + + ;
                start + + ;
            }
            arr[j] = '\0';
            i + + ;
            if (i < s.length())
            {
                endStr + + ;
                start = endStr;

            }

            if (arr[0] != '\0')
                stringVector.push_back(arr);
            delete[]arr;
            arr = NULL;
            //cout<<"Split once"<<endl;
        }
        else
        {
            i + + ;//13
            if (i < s.length())
                endStr + + ;
            else//Determine whether the current endStr points to str or other characters
            {
                if (*endStr == str)
                {
                    int size = endStr - start;
                    char* arr = new char[size + 1];
                    int j = 0;
                    while (start != endStr)
                    {
                        arr[j] = *start;
                        j + + ;
                        start + + ;
                    }
                    arr[j] = '\0';
                    stringVector.push_back(arr);
                    delete[]arr;
                    arr = NULL;
                }
                else
                {

                    const int size = endStr - start;
                    /*At this time endStr points to the last non-str character
                      Because it also needs to exist, the length must be + 1
                    */
                    char* arr = new char[size + 2];//+ 1 again to reserve '\0'
                    int j = 0;
                    while (j <= size)//Cannot judge start<=endStr or start!=endStr
                    {
                        arr[j] = *start;
                        j + + ;
                        start + + ;
                    }
                    arr[j] = '\0';
                    stringVector.push_back(arr);
                    delete[]arr;
                    arr = NULL;
                }


            }
            // cout<<"Undivided"<<endl;
        }

    }
}