I'm new in NSIS and C++.
I write a NSIS plugin to check a license with http request with VS2010.
But the plugin only work on the computers with VS2010 installed.
I guess the reason is the libraries like "ws2_32.lib" is not bundled in the package.
I want the installation package with this plugin worked on the computers without C++ installed.
Is there any idea how to solve it?
Thanks a lot.
Here is my code.
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <WinSock2.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
#include <string.h>
#include <stdio.h>
#include "./../nsis/pluginapi.h"
#include <windows.h>
#include <Wincrypt.h>
#pragma comment(lib,"crypt32")
#pragma comment(lib,"./../nsis/pluginapi-x86-unicode.lib")
#pragma comment(lib, "ws2_32.lib")
void __declspec(dllexport) myFunction(HWND hwndParent, int string_size,
TCHAR *variables, stack_t **stacktop,
extra_parameters *extra)
{
g_hwndParent = hwndParent;
EXDLL_INIT();
//读取输入参数
WCHAR szComponent[256];
popstring(szComponent);
//打印参数
WCHAR buf[1024];
//这里能正确打印出来自NSIS的中文信息。
//wsprintf(buf, L"kagula $0=[%s][szComponent]\n", szComponent);
//MessageBoxW(g_hwndParent, buf, 0, MB_OK);
WCHAR urlComponent[256];
popstring(urlComponent);
//wsprintf(buf, L"kagula $0=[%s][urlComponent]\n", urlComponent);
//MessageBoxW(g_hwndParent, buf, 0, MB_OK);
WCHAR ipComponent[256];
popstring(ipComponent);
WCHAR portComponent[256];
popstring(portComponent);
//准备返回参考
int len = (int)wcslen(szComponent);
int input_len = (int)wcslen(szComponent);
//printf("%d\n", input_len);
//char server_id[256];
//for (int i = 0; i <
char* server_id = wchar2char(szComponent);
printf("%d\n", strlen(server_id));
//char* server_id = new char(256);
//for (int i = 0; i < input_len; i++) {
// server_id[i] = szComponent[i];
//}
//to_narrow(szComponent, server_id, 256);
printf("serid %s", server_id);
//打印参数
char* ret = ""; // 返回Http Response
try
{
// 开始进行socket初始化
WSADATA wData;
::WSAStartup(MAKEWORD(2, 2), &wData);
SOCKET clientSocket = socket(AF_INET, 1, 0);
struct sockaddr_in ServerAddr = {0};
char* m_ip = wchar2char(ipComponent);
int m_port = atoi(wchar2char(portComponent));
char* req = wchar2char(urlComponent);
WCHAR bufchar[3069];
//这里能正确打印出来自NSIS的中文信息。
//wsprintf(bufchar, L"kagula $0=[%s][server_id]\n", char2wchar(server_id));
//MessageBoxW(g_hwndParent, bufchar, 0, MB_OK);
printf("req %s", req);
char* urlSend = (char*) malloc(strlen(req) + strlen(server_id));
strcpy(urlSend, req);
strcat(urlSend, server_id);
//strcat(req, server_id);
printf("req %s", req);
ServerAddr.sin_addr.s_addr = inet_addr(m_ip);
ServerAddr.sin_port = htons(m_port);
ServerAddr.sin_family = AF_INET;
int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));
printf("errNo connect %d \n", errNo);
if(errNo == 0)
{
// "GET /[req] HTTP/1.1\r\n"
// "Connection:Keep-Alive\r\n"
// "Accept-Encoding:gzip, deflate\r\n"
// "Accept-Language:zh-CN,en,*\r\n"
// "User-Agent:Mozilla/5.0\r\n\r\n";
char* cookie = " HTTP/1.1\r\nCookie:16888\r\n\r\n";
// strSend = "GET " + req + strSend;
char* gp = "GET ";
char* strSend = (char*) malloc(strlen(gp) + strlen(cookie) + strlen(urlSend));
strcpy(strSend, gp);
strcat(strSend, urlSend);
strcat(strSend, cookie);
// 发送
errNo = send(clientSocket, strSend, strlen(strSend), 0);
if(errNo > 0)
{
//cout << "发送成功" << endl;
}
else
{
//std::cout << "errNo:" << errNo << std::endl;
printf("errNo:");
// return ret;
}
// 接收
char bufRecv[3069] = {0};
errNo = recv(clientSocket, bufRecv, 3069, 0);
if(errNo > 0)
{
ret = bufRecv;// 如果接收成功,则返回接收的数据内容
}
else
{
// std::cout << "errNo:" << errNo << std::endl;
printf("errNo:");
// return ret;
}
}
else
{
errNo = WSAGetLastError();
// std::cout << "errNo:" << errNo << std::endl;
printf("errNo:");
printf(errNo + "");
}
// socket环境清理
::WSACleanup();
}
catch (...)
{
// return "";
}
printf(ret);
// push back on the stack
TCHAR * tchar;
char* ok_str = "ServerId is OK";
if(strstr(ret, ok_str) == NULL) {
tchar = _T("0");
} else {
tchar = _T("1");
}
for (int i = 0; i < len; ++i) {
printf("%d", i);
szComponent[i] += 1;
}
pushstring(tchar);
}
I guess the reason is the libraries like "ws2_32.lib" is not bundled in the package.
No, that thing is only consumed by Visual C++ linker. In runtime, the corresponding DLL is taken from C:\Windows\System32\ws2_32.dll
Most likely reason is C and C++ runtime DLLs. By default, Visual Studio C++ projects use dynamic linking to these libraries. For an installer plugin, a good way to fix is switch to static C++ runtime. Right click on the project, Configuration properties, C/C++, Code Generation, change the “Runtime Library” setting to Multi-threaded Debug (/MTd) for debug configuration and Multi-threaded (/MT) for release configuration.
P.S. I would recommend a higher-level library for HTTP networking, such as WinHTTP or WinINet. Modern Internet has migrated from http to https.
Related
main
#include "stdafx.h"
#include <iostream>
#include "SerialPort.h"
#include <WinBase.h>
using namespace std;
int main()
{
cout << "Monitoring System \n";
cout << "Please select a connection method\n\n";
cout << "1.Serial 2.TCP \n";
int num;
while (!(cin >> num))
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Please enter a number only ";
}
if(num==1)
{
int i,SN;
int k=0;
cout << "Scan all ports that are currently...\n";
for (i = 1; i < 30; ++i)
{
if (COM_exists(i))
{
cout <<++k<< ".COM" << i << "\n";
}
}
cout << "\nselect a port to connect.\n";
scanf_s("%d", &SN, sizeof SN);
if (SN == 1)
{
SerialPort PortOpen("COM", CBR_115200, 8, "#or", 24);
PortOpen.getData();
PortOpen.getData();
cout << PortOpen.SerialBuffer << endl;
return 0;
}
}
}
serial cpp
#include "stdafx.h"
#include <string.h>
#include "SerialPort.h"
using namespace std;
BOOL COM_exists(int port)
{
char buffer[7];
COMMCONFIG CommConfig;
DWORD size;
if (!(1 <= port && port <= 30))
{
return FALSE;
}
snprintf(buffer, sizeof buffer, "COM%d", port);
size = sizeof CommConfig;
// COM port exists if GetDefaultCommConfig returns TRUE
// or changes <size> to indicate COMMCONFIG buffer too small.
return (GetDefaultCommConfig(buffer, &CommConfig, &size)
|| size > sizeof CommConfig);
}
SerialPort::SerialPort(LPCSTR COM,int setBaudRate, int setByteSize, char* commandBuffer, int BufSize) {
this->BufSize = BufSize;
this->SerialBuffer = new char[BufSize];
this->NoBytesRead = BufSize;
Connect(COM, setBaudRate, setByteSize, commandBuffer);
}
void SerialPort::Connect(LPCSTR COM ,int setBaudRate, int setByteSize, char* commandBuffer) {
this->COMport = COM;
this->hComm = CreateFile(COM, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); // (port name, read/write , no sharing , no security, open existing port only, non overlapped i/o , null for comm devices)
if (this->hComm == INVALID_HANDLE_VALUE)
cout << "PortOpen Fail." << endl;
else {
cout << "PortOpen Success." << endl;
sendCommand(setBaudRate, setByteSize, commandBuffer);
}
}
void SerialPort::sendCommand(int setBaudRate, int setByteSize, char* commandBuffer) {
this->commandBuffer = commandBuffer;
this->dNoOFBytestoWrite = sizeof(commandBuffer);
this->Status = WriteFile(hComm, commandBuffer, dNoOFBytestoWrite, &dNoOfBytesWritten, NULL);
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
dcbSerialParams.BaudRate = setBaudRate;
dcbSerialParams.ByteSize = setByteSize;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 10;
timeouts.ReadTotalTimeoutConstant = 10;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (this->Status)
cout << "Command Successful" << endl;
else
{
cout << "fail to Command" << endl;
}
}
void SerialPort::getData() {
ReadFile(this->hComm, &*this->SerialBuffer, this->BufSize, &this->NoBytesRead, NULL);
}
SerialPort.h
#pragma once
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <WinBase.h>
using namespace std;
class SerialPort {
public:
HANDLE hComm;
LPCSTR COMport;
DWORD dNoOFBytestoWrite;
DWORD dNoOfBytesWritten;
int BufSize;
int Status;
char* SerialBuffer;
char* commandBuffer;
DWORD NoBytesRead;
int port;
SerialPort(LPCSTR COMport,int setBaudRate, int setByteSize, char* commandBuffer, int BufSize);
void Connect(LPCSTR COMport, int setBaudRate, int setByteSize, char* commandBuffer);
void sendCommand(int setBaudRate, int setByteSize, char* commandBuffer);
void getData();
};
BOOL COM_exists(int port);
I am writing a code to connect by selecting a serial port.
example, 1.COM1 / 2.COM3 / 3.COM4
How do I modify the main to connect COM4 that matches No. 3?
How do I automatically read and use matching ports to match numbers?
I am writing a code to connect by selecting a serial port.
example, 1.COM1 / 2.COM3 / 3.COM4
How do I modify the main to connect COM4 that matches No. 3?
How do I automatically read and use matching ports to match numbers?
I would personally never ever use the old school style open and close COM port to detect if it exists.
Assuming you are running on Windows I would use the SetupDi to find the serial port without opening it.
A little snippet to adapt:
#include <initguid.h>
#include <windows.h> // Data Type
#include <setupapi.h> // ::SetupDi*********
#include <devguid.h> // Device
// Global Variables
HDEVINFO m_hDevInfo; //!< Reference to device information set
SP_DEVINFO_DATA m_spDevInfoData; //!< Device information structure (references a device instance that is a member of a device information set)
BOOL m_bDevInfo; //!< Tested to ensure EnumDeviceInfo has been called
short m_MemberIndex = -1; //!< Preserves state between EnumDeviceInfo calls
bool WIN_EnumDeviceInfo ()
{
m_MemberIndex++;
m_spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
m_bDevInfo = ::SetupDiEnumDeviceInfo(m_hDevInfo, m_MemberIndex, &m_spDevInfoData);
return m_bDevInfo;
}
bool WIN_GetDeviceRegistryProperty(DWORD Property, PBYTE PropertyBuffer)
{
BOOL bGotRegProp = ::SetupDiGetDeviceRegistryProperty(m_hDevInfo, &m_spDevInfoData,
Property,
0L,
PropertyBuffer,
2048,
0);
return bGotRegProp;
}
void ScanSerial()
{
WORD Flags;
PCWSTR Enumerator=0;
const GUID *ClassGuid;
HWND m_hWnd;
ClassGuid = &GUID_DEVCLASS_PORTS;
Flags = DIGCF_PROFILE;
m_hDevInfo = SetupDiGetClassDevs(ClassGuid, Enumerator, m_hWnd, Flags);
while(WIN_EnumDeviceInfo())
{
wchar_t szBuf[MAX_PATH] = {0};
if(WIN_GetDeviceRegistryProperty(SPDRP_CLASS, (PBYTE)szBuf))
{
wchar_t szFriendlyName[MAX_PATH] = {0};
WIN_GetDeviceRegistryProperty (SPDRP_FRIENDLYNAME, (PBYTE)szFriendlyName);
}
}
}
From the szFriendlyName you can filter the COMx number without opening it or either confusing them...
Try and enjoy...
I am actually programming a simple server and it's client in c++ using the tcp protocol. As this is to be integrated in a multiplayer game, every client has to send data extremely fast.
Issue: The server's buffer sometimes gets multiple messages in it.
I tried various things like putting off nagle's algorithm but I didn't manage to fix this problem. Here's the server's code :
#ifdef __linux__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
#define SOCKET int
#define SOCKADDR_IN struct sockaddr_in
#endif
#ifdef _WIN32
#include <winsock2.h>
#endif
#include <cstdio>
#include <iostream>
#include <thread>
#include <vector>
#include <string>
#include "server.h"
#include "../../Logger/logger.h"
#include "../../AltisCraft.fr/Map/map.h"
#include "../../StringPlus/string_plus.h"
#include "../../AltisCraft.fr/Map/User/User.h"
void connectEvent(), receive(), sendAllUsers(string), closeConnectio(),manageMsg();
vector<SOCKET> clients;
vector<thread> clientsThreads;
vector<string> msg;
SOCKET socketId, newSocketId;
SOCKADDR_IN source;
thread connection;
char buffer[65535] = {0};
int position;
// TODO: crypt every data sendLog/receive
// TODO: whitelist ip serv
// TODO: Auth system
// TODO: timer with packet ? (double receive...)
int sendLog(SOCKET s, const char* c, int i0, int i1)
{
log("Send:");
log(c);
send(s, c, i0, i1);
}
void initializeNetwork()
{
#ifdef _WIN32
WSADATA initWin32;
WSAStartup(MAKEWORD(2, 2),&initWin32);
#endif
socketId = socket(AF_INET, SOCK_STREAM, 0);
source.sin_family = AF_INET;
source.sin_addr.s_addr = INADDR_ANY;
source.sin_port = htons(33333);
bind(socketId, (struct sockaddr*)&source, sizeof(source));
connection = thread(&connectEvent);
connection.join();
closeConnection();
}
void connectEvent()
{
int error;
while(1)
{
error = 99;
while(error != 0)
{
error = listen(socketId, 1);
}
#ifdef _WIN32
int tempo = sizeof(source);
newSocketId = accept(socketId, (struct sockaddr*)&source, &tempo);
clients.push_back(newSocketId);
#endif
#ifdef __linux__
socklen_t tempo;
newSocketId = accept(socketId, (struct sockaddr *)&source, &tempo);
clients.push_back(newSocketId);
#endif
clientsThreads.push_back(thread(&receive));
}
}
void receive()
{
int val = 1;
position = clients.size() - 1;
bool connected = 1;
while(connected)
{
buffer[65535] = {0};
if(recv(clients[position], buffer, 1515, 0) > 0)
{
string msg = buffer;
bool isEmpty = false;
log(string(inet_ntoa(source.sin_addr)) + ": " + msg);
if(startsWith(msg, "Connect "))
addUser(replace(msg, "Connect ", ""));
else if(msg == "MAJ Map")
{
log(elements);
string toSend = "MAJ Map\n" + elements;
sendLog(clients[position], toSend.c_str(), strlen(toSend.c_str()), 0);
}
else if(startsWith(msg, "MAJ User ")) /// optimize: don't sendLog pos to player who sendLog
{
msg = replace(msg, "MAJ User ", "");
if(startsWith(msg, "Pos "))
{
msg = replace(msg, "Pos ", "");
vector<string> elements = split(msg, " ");
User user = *getUserByName(elements[0] + " " + elements[1]);
user.updateView(user.getView().updatePosition(Position(convertStrToDouble(elements[2]), convertStrToDouble(elements[3]), convertStrToDouble(elements[4]))));
}
else if(startsWith(msg, "ViewAngle "))
{
msg = replace(msg, "ViewAngle ", "");
vector<string> elements = split(msg, " ");
User user = *getUserByName(elements[0] + " " + elements[1]);
user.updateView(user.getView().updateViewAngle(ViewAngle(convertStrToDouble(elements[2]), convertStrToDouble(elements[3]))));
}
}
else
sendAllUsers(string(string(inet_ntoa(source.sin_addr)) + ": " + msg).c_str());
}
else
connected = 0;
}
shutdown(clients[position], 2);
for(int i=0;i<msg.size();i++)
cout << msg[i] << endl;
#ifdef _WIN32
closesocket(clients[position]);
#endif
#ifdef __linux__
close(clients[position]);
#endif
clients.erase(clients.begin() + position);
}
void sendAllUsersWithoutOne(string msg, string name)
{
for(int j = 0; j < (int)clients.size(); j++)
{
// only linux here (MSG_DONTWAIT)
#ifdef __linux__
if(recv(clients[j], NULL, 1, MSG_PEEK | MSG_DONTWAIT) == 0)
{
clients.erase(clients.begin() + j);
continue;
}
#endif
sendLog(clients[j], msg.c_str(), strlen(msg.c_str()), 0);
}
}
void sendAllUsers(string msg)
{
for(int j = 0; j < (int)clients.size(); j++)
{
// only linux here (MSG_DONTWAIT)
#ifdef __linux__
if(recv(clients[j], NULL, 1, MSG_PEEK | MSG_DONTWAIT) == 0)
{
clients.erase(clients.begin() + j);
continue;
}
#endif
sendLog(clients[j], msg.c_str(), strlen(msg.c_str()), 0);
}
}
void closeConnection()
{
for(int i = 0; i < (int)clients.size(); i++)
{
shutdown(clients[i], 2);
#ifdef _WIN32
closesocket(clients[i]);
#endif
#ifdef __linux__
close(clients[i]);
#endif
}
#ifdef _WIN32
closesocket(socketId);
WSACleanup();
#endif
#ifdef __linux__
close(socketId);
#endif
}
void freeNetwork()
{
closeConnection();
}`
to expand on Barmar's comment
TCP is a streaming protocol, not a message protocol. THe only guarantee is that you send n bytes, you will receive n bytes in the same order.
You might send 1 chunk of 100 bytes and receive 100 1 byte recvs, or you might receive 20 5 bytes recvs
You could send 100 1 byte chunks and receive 4 25 byte messages
You must deal with message boundaries yourself. Either have a sentinel value to mark start and end or prepend a length that is a fixed size itself (so you know you have read the whole length). Then loop on recv till you have received the whole message
I'm a green hand coder from China. I met some problem in using the google-geocoding-api, it is correct when I debug with the following code, but there is no response when I use the gennerated .exe file compile in release mode。Cause I am in China,So I can just use the net agent to visit the URL,so I don't kown wheteher it is the problem of net work or the problem of my code. Could someone help me to try the following code to check the exactly problem.
// street_name.cpp :
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <Windows.h>
#include <wininet.h>
using namespace std;
#define MAXBLOCKSIZE 500
#pragma comment (lib, "wininet.lib")
void download(const char*);
int main(int argc, char* argv[]){
const char *cUrl = NULL;
char Url[512];
float lat = 45.798748;
float lng = 126.531115;
sprintf(Url,"https://maps.googleapis.com/maps/api/geocode/xml?latlng=45.797749,126.523811&result_type=route&address_component_type=route&key=AIzaSyC6M3Pbbjdrgtl8QZjuJPK-1JdAJD5oEgA",lat,lng);
cUrl = Url;
download(cUrl);
if (argc > 1)
{
download((const char*)argv[1]);
}
else
{
cout << "Usage: auto-Update url";
}
return 0;
}
/**
*
* #param Url: The target action url
*
*/
void download(const char *Url)
{
HINTERNET hSession = InternetOpenA("RookIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
string StreetName;
if (hSession != NULL)
{
HINTERNET handle2 = InternetOpenUrlA(hSession, Url, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if (handle2 != NULL)
{
cout << Url << endl;
byte Temp[MAXBLOCKSIZE] = {0};
ULONG Number = 1;
int i = 0;
ofstream ofs("baidu.txt");
if (ofs)
{
while (Number > 0)
{
InternetReadFile(handle2, Temp, MAXBLOCKSIZE - 1, &Number);
string a = string((const char*)Temp,Number);
ofs << a.c_str();
StreetName += a;
}
ofs.close();
}
InternetCloseHandle(handle2);
handle2 = NULL;
}
InternetCloseHandle(hSession);
hSession = NULL;
}
}
If your requests are coming from China, it may be that HTTPS requests are blocked. Try HTTP.
I'm thinking this may be related to https://meta.stackexchange.com/questions/191338/https-problem-when-accessing-stack-overflow-in-china
I'm currently attempting to build a simple C++ program to insert a record into a MS Sql Server database. The code executes and return codes indicate that things technically worked, yet no record is actually getting inserted to the database. I'm at a lose as to what might be causing the issue. Driver maybe?
Originally I intended to use prepared statements and avoid any string copying, but I couldn't seem to get those to work properly. So, to test if anything would happen at all, I build a query as below. Not the best approach and not my intended approach but I can't even seem to get a record inserted to the db.
Return codes do not indicate problems with the connection (please note, I've changed the actual connection information) or even the execution of the query, which leans me towards perhaps needing a commit? Also why I might be inclined to think it is the driver. Thoughts?
Here is the code:
stdafx.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here
#include <Windows.h>
#include <winnt.h>
#include <sqlext.h>
#include <rpc.h>
#include <iostream>
#pragma comment(lib, "rpcrt4.lib")
And testCamel2Db.cpp
// testCamel2Db.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
INT connectDb(VOID);
int _tmain(int argc, _TCHAR* argv[])
{
connectDb();
return 0;
}
INT connectDb (VOID)
{
RETCODE rc; //ODBC return code
HENV henv; //environment handle
HSTMT hstmt;//statement handle
HDBC hdbc; //connection handle
SQLAllocEnv(&henv);
SQLAllocConnect(henv, &hdbc);
rc = SQLDriverConnect(
hdbc,
NULL,
(unsigned char*)"DRIVER={SQL Server};SERVER=server.name.edu,3433;DATABASE=camel2;UID=username;PWD=password;",
SQL_NTS,
NULL,
0,
NULL,
SQL_DRIVER_COMPLETE);
if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
{
//error handling here
std::cout << "no connection created.";
return 1;
}
//create a uuid
UUID uuid;
UuidCreate(&uuid);
unsigned char* uuidStr;
UuidToStringA(&uuid,&uuidStr);
INT quotedUuidSize = strlen((char*)uuidStr) + 2;
char* quotedUuidStr = new char[quotedUuidSize +1];
memset(quotedUuidStr, 0, sizeof(char) * quotedUuidSize + 1);
strcat(quotedUuidStr, "'");
strcat(quotedUuidStr, (char*)uuidStr);
strcat(quotedUuidStr, "'");
//admin_user variable
LPSTR adminUser;
adminUser = "'Active Directory'";
//build a query
LPSTR sql = "INSERT cw_ResetCheck (ResetUID, AdminUser ) values (";
INT queryStrSize = strlen(sql) + strlen((char*)quotedUuidStr) + strlen(adminUser) + 2;
char* queryStr = new char[queryStrSize + 1];
memset(queryStr, 0, sizeof(char) * (queryStrSize + 1));
strcat(queryStr,sql);
strcat(queryStr,(char*)quotedUuidStr);
strcat(queryStr,",");
strcat(queryStr,adminUser);
strcat(queryStr,")");
std::cout << queryStr << "\n";
rc = SQLAllocStmt(hdbc,&hstmt);
std::cout << uuidStr;
rc = SQLExecDirect(hstmt, (SQLCHAR*)queryStr, SQL_NTS);
if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
{
std::cout << "query failed";
return 1;
}
else
{
std::cout << "uid created: ";
std::cout << uuidStr;
}
//close database
SQLFreeStmt(hstmt,SQL_DROP);
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
return 0;
}
I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.