Push Framework - A C++ toolkit for high performance server development in Windows
- Download library source code (VC++ 2008) - 133 KB
- Download library essentials (lib + public headers + DLL) - 70.9 KB
- Download Demo 1: Chat application (Server + Client + XMLProtocol + TCPSocket Module) - 292 KB
- Download Demo 2: Google ProtoBuf integration example (Server + Client + ProtoBufProtocol Module) - 33.9 KB
- Download QoS validation application (Client + Server + Protocol Module) - 20.5 KB
- Download ChatBots simulator (Traffic generator for testing purpose) - 6.7 KB
Table of contents
- Introduction
- Deployment layout
- The developer perspective
- Technical architecture
- Tutorials and examples
- Benchmarking
- References
- History
Introduction
Beyond websites, there are other types of applications which -if not impossible- can not be easily built using the web. What the web offers as a technology is good for situations where we need to publish content and ensure the immediate and easy deployment of changes incurred to it. The user only reacts to content. If he reacts with other users, then its "reaction" is compiled into the content, persisted, then shown to others when they request it. Applications that need to broadcast information in real time, or applications that want to enable connected users to "engage" with each other in real time need a dedicated technology.
For the simplest example, think of a chat application, or a media streaming server. You can also think about many sophisticated applications that collect signals from a large number of remotely connected devices and provide a timely decision. Such technology should be able to manage a large number of active full duplex connections. It should be able to relay information from a connection to another one in an immediate way and enable the efficient and asynchronous broadcast of information so that spontaneous and timely responses are received by the client-side. I would like to give you my contribution here in the form of a C++ library which emerged from multiple refactoring of the server side code of an amateur chess server I am developing, and which I hope people may find useful for other domains as well. Beyond this article, you can find articles, complete documentation guides, and other helpful material at the Push Framework home page: http://www.pushframework.com.
Deployment layout
Let us look at the deployment picture here. Your server logic will be written on top of the Push Framework library. It is clear if you want to deploy the application, then you need a dedicated server machine. You should design / use a protocol that helps the efficient communication between your client side application and the server side of it. Clients will connect to a TCP port that you specify. It is possible that you have heterogeneous clients which use different protocols to talk with your server. One major feature of the library however is its ability to profile itself and send periodic statistics. You just need to activate that feature with a simple API call and connect the Dashboard, a separately developed Applet, to the "monitoring" port of the server so you can receive the "feed" of those stats.
The developer perspective
Personally, as a developer, when I discover a new library and want to asses it, I hurry to look at an example usage code. From there, I can see the big picture. So let me sacrifice many essential details here and only report the main view. A single instance encapsulates all of the library functionalities:
PushFramework::Server server;
Configure such an instance by calling the member methods, then call start
to run your server. This is how the code surrounding that instance would look like when you are finished:
PushFramework::Server server;
server.setClientFactory(pClientFactory);
server.setProtocol(pProtocol);
server.createListener(sPort);
server.registerService(myServiceId, pService, "myService";
//
server.start(false);
Now questions are raised. Well first, pClientFactory
should point to a concrete implementation of the PushFramework::ClientFactory
class. This class manages the client connection/disconnection; it also manages the transition when a socket connection gets translated into a legitimate client which could be discovered by others. It also manages the case when a client reconnects (abrupt TCP failures can happen, then the same client reconnects) and when we need to bind the new TCP socket to the existing client information and previously allocated resources. Note that in the servicing code, you never deal with the socket, you rather deal with PushFramework::Client
instances representing your active clients.
The protocol is an all essential information. You pass this by providing a concrete implementation of the PushFramework::Protocol
class to the ::setProtocol
method or within the ListenerOptions
parameter of ::createListener
if you intend to support multiple protocols. By overriding its pure methods, you will tell the library how the received information should be deserialized and how the outgoing information should be serialized. To send an information to a specific client or to a specific group of clients (broadcast), PushFramework expects input in the form of instances of type PushFramework::OutgoingPacket
. Encoding and framing is acted upon such a class. When data is received, decoding and deframing are triggered and that is called de-serialization. At the end of the day, deserialized data is communicated back in the form of IncomingPacket
instances. These instances are dispatched to your "servicing code" which you may find it useful to organize into many "services" (very useful when there are multiple types of requests that can be received with each type requiring a special processing).
A service is materialized by an instance of a PushFramework::Service
subclass. You devise your business logic by overriding the handle method of it, then you affect an ID to the instance. Of course, you should take care of passing that ID information at de-serialization time so the library knows how to route the packets.
Let us see how you can treat incoming data. In the first case, we will handle a particular request and echo back a response to the requestor:
MyService::handle(ClinetKey key, IncomingPacket& pPacket)
{
CMyClient* pClient = getClient(key);
if(pClient)
{
//See what client wants by examining pPacket
//Send response
OutgoingPacket response;
//build your response
pClient->push(&response);
returnClient(key);
}
}
The library is multithreaded. To be more precise, multiple threads are spawn to execute the servicing code. So the code in the handle
method of your Service subclasses is a concurrent one. The library maintains reference counters for each Client instance so that the safe release of instances is achieved. Let us consider this example where information has to be relayed from a connection to another connection. Imagine we are in the context of a chat application:
MyService::handle(ClinetKey key, IncomingPacket& pPacket)
{
CMyClient* pClient = getClient(key);
if(pClient)
{
ClientKey recipientKey;// furnish this info from pPacket
char* msg// to be furnished from pPacket.
CMyClient* pRecipient = getClient(recipientKey);
if(pRecipient)
{
OutgoingPacket response;
//build the chat response by putting the sender info and the msg
pRecipient->push(&response);
returnClient(recipientKey);
}
returnClient(key);
}
}
Finally, let us see how to send broadcast information.
MyService2: public PushFramework::Service
{
void handle(ClientKey key, PushFramework::IncomingPacket& request)
{
MyClient* pClient = getClient(key);
if(pClient)
{
//Do something eg.
PushFramework::OutgoingPacket* pResponse = new PushFramework::OutgoingPacket();
getBroadcastManager()->pushPacket("broadcastGroup1", pResponse);
returnClient(key);
}
}
}
Technical architecture
It is good to have a look at the internals of the library even though you would only find yourself dealing with a handful of public classes that encapsulate all the details. Let me ease it by enumerating the notes.
- The library uses the powerful mechanism of Windows Server IOCP. Asynchronous IOs are issued by Worker threads managed at the library layer, and their completions are notified back by the OS in the form of completion packets into sort of a Multiple-Producers Multiple Consumers Queue. By default, the library sets up the number of threads according to the available processors. Interestingly, when such a thread blocks on the servicing code, the system awakes another worker to let the efficient use of available calculus resources.
- The main thread is the one that manages the different parts of the system: it launches the separate listening threads, the worker threads, schedules periodic tasks, and listens on the termination signal so it can stop all threads and clean all memory.
- Listening is performed by a separate thread. Incoming connection requests are communicated to the Channels factory. There happens the decision to associate the connection with a new Client object or to attach it to an existing one (client reconnection identification).
- The Demux communicates the sending/receiving operation completion status back to the dispatcher. When a Write operation finishes, the intermediate Send buffer is examined for any outstanding data to be sent. The intermediate buffer is filled by explicit calls to Send operations and an internal mechanism of streaming broadcast responses. If a Read operation completes, the dispatcher triggers de-serialization which in turn calls the protocol-defined de-framing and decoding code, then gives back control to the handle method of the Service object responsible for the incoming request type.
- Most of the execution time is spent on the available
Service::handle
methods. There you put the processing logic for each type of incoming request. Naturally, there you would push data to specific clients or to a broadcasting channel so the library implicitly streams the information to the list of clients that are subscribed. - Each broadcasting channel has four attributes:
requireSubscription
,maxPacket
,priority
, andquota
. IfrequireSubscription
isfalse
, then all logged clients are implicitly subscribed to it. Otherwise, you must explicitly register each client you want. - Each broadcasting channel maintains a FIFO queue of the packets that are pushed into it.
maxPacket
is its maximum size. Ancient packets get released when the queue is full. Avoiding the phenomenon of broadcast amplification (uncontrollable increased memory consumption) comes at the cost of packet loss for those clients with B(i) < F(j) where B(i) is the available bandwidth between the server and the client i, and F(j) is the fill rate of broadcasting channel j which i is subscribed to. - When the bandwidth between a certain client x and the server along with the server’s degree of activity are such that not all data can be streamed out, the share of each broadcasting channel to which client x is subscribed is dependent on the priority and quotas attributes.
- Suppose that broadcasting channels {Ci} are ordered in such way that if i < j => (either Pi > Pj or (Pi = Pj and Qi >= Qj)), P and Q being the priority and quota attributes.
- Let’s denote Fi as the rate at which Ci is filled with new packets.
- Let’s assume S to be the total rate of broadcast data sent to client x.
- Further assuming that all outgoing messages have the same length.
- The monitoring listener is started in case remote monitoring is enabled. It helps accept connections from remote Dashboards so profiling info are sent.
Then, the share Si of broadcasting channel i is given by:
Tutorials and examples
Chat application
The best way you can see the Push Framework in action is to guide you in the development of a whole new application that will be based on it. This allows to better assess the library and weigh multiple factors at once.
You can follow the step-by-step tutorial here. Source code and binaries are also available.
The application that is developed uses XML to encode requests and responses. The server and the client "see" the same prototypes that represent those requests/responses. If a direct chat message is received, the server knows the destination client and forwards the request to the relevant connection. At startup, the chat server creates broadcasting channels to represent the "available chat rooms". If a room chat request is received, a room chat response is pushed into the corresponding broadcasting channel so every participant in the room receives that response. Joining a room is technically implemented by "subscribing" a client to a broadcasting channel. The same goes for how to let chat participants see each other: a broadcasting channel is setup and filled with signal packets each time a client logs in.
Client-server using the Google Protobuf protocol
Google says it created its own protocol to let its heterogeneous applications exchange data. Encoding/decoding is extremely fast and produces a minimum message. To allows users who want to use this protocol along side Push Framework, a client-server application is created. You can follow the complete tutorial here. The functionality is extremely simple: the client sends a request about some item with a particular ID. The response is expected to contain the detailed information about that item. One can imagine anything, the aim here is just to let the integration between ProtoBuf and the Push Framework be understood.
Communication data must be designed in a specific language before being compiled by ProtoBuf so we can produce the classes with which we can work with. For our example, we need to design these three structures only:
// content of loginrequest.proto :
package gprotoexample;
message LoginRequest {
}
//content of loginresponse.proto
package gprotoexample;
message LoginResponse {
required bool result = true;
}
//content of datainforrequest.proto
package gprotoexample;
message DataInfoRequest {
required int32 id = 2; // id for item.
}
//content of datainforesponse.proto
package gprotoexample;
message DataInfoResponse {
enum ResultType {
InfoFound = 0;
InfoNotFound = 1;
InfounspecifiedError = 2;
}
required ResultType result = 0;
required int32 id = 1; //
optional string description = 1;
}
//content of logoutrequest.proto
package gprotoexample;
message LoginResponse {
required bool result = true;
}
For use with C++, the ProtoBuf compiler produces C++ classes that we include in our project. To adapt ProtoBuf and allow multiple messages to be sent in the same connection (ProtoBuf messages are not self delimiting), we create a new PushFramework::Protocol
subclass alongside a template class, deriving both from PushFramework::OutgoingPacket
and PushFramework::IncomingPacket
which are the currency for the Push Framework:
class ProtobufPacketImpl : public PushFramework::IncomingPacket,
public PushFramework::OutgoingPacket
{
public:
ProtobufPacketImpl(int serviceId);
~ProtobufPacketImpl(void);
protected:
virtual bool Decode(char* pBuf, unsigned int nSize);
virtual bool Encode();
virtual google::protobuf::Message& getStructuredData() = 0;
private:
int serviceId;
std::string* pEncodedStream;
public:
std::string* getEncodedStream() const { return pEncodedStream; }
int getEncodedStreamSize();
int getServiceId() const { return serviceId; }
};
template<class T>
class ProtobufPacket : public ProtobufPacketImpl
{
public:
ProtobufPacket(int serviceId)
: ProtobufPacketImpl(serviceId)
{
//
}
~ProtobufPacket()
{
//
}
private:
T data;
public:
virtual google::protobuf::Message& getStructuredData()
{
return data;
}
};
Here is how the servicing code looks like when we receive a datainforequest
:
void CDataInfoRequestService::handle( ClientKey clientKey,
PushFramework::IncomingPacket* pRequest )
{
ExampleClient* pClient = (ExampleClient*) getClient(clientKey);
if(!pClient)
return;
ProtobufPacket<DataInfoRequest>* pDataInfoRequest =
(ProtobufPacket<DataInfoRequest>*) pRequest;
ProtobufPacket<DataInfoResponse> response(DataInfoResponseID);
response.getData().set_id(pDataInfoRequest->getData().id());
response.getData().set_result(DataInfoResponse_ResultType_InfoFound);
response.getData().set_description("this is a description");
//
pClient->pushPacket(&response);
returnClient(clientKey);
}
Benchmarking
Monitoring the chat application
An interesting feature of the Push Framework is its ability to profile itself and send a real time report to a remote Dashboard where the numbers are drawn into usable display in the form of qualitative charts and grids. You activate this by calling a simple method of your server object:
//Assuming server is your Server instance
server.enableRemoteMonitor(monitoringPort, password);
//And to activate profiling, you do :
server.enableProfiling(samplingRate);
monitoringPort
is the listening port that the Monitoring Listener will listen to. Of course, you will have to put that information in the Dashboard login info along with the server IP and password so your connection succeeds. The dashboard can be used to execute remote commands. By overriding Server::handleMonitorRequest
, you can receive any input that your user tapes in the Dashboard console. The answer is redirected in the form of a text in the console. Statistics and Performance information can not be displayed in the Dashboard unless you make a call to Server::enableProfiling
. This instructs the library to start to collect performance values and send a report at a regular interval of samplingRate
seconds.
The aim now is to let you see the use of the remote monitoring features. So let's enable profiling in the previously developed chat server and try to connect to the server using the Monitoring Dashboard. To be close to a real world scenario where a very large number of people connect to the same chat server and chat with each other, I've made a separate multi-clients simulator able to launch many connections and approximately behave like a human participant who sends chats, replies to receive chat, and also engages in chat rooms. This is contained in the ChatRobots project. The Simulator is- to tell the truth- not very optimized because it launches one thread for each Chat Robot. So this can lead to some issues when launching many clients.
In one test, 100 bots were started against the previous chat server which reports profiling at intervals of 10s duration. The following is a screenshot of the Performance tab of the Dashboard:
You can find other screenshots and read details in this article: Bursting the Library. A zoom on the Time Processing Zone gives:
The vertical segments represent the periodic report that is sent every 10 seconds. The segment center is the average processing time of all the requests that were received within the specific observation interval. The vertical length is the dispersion calculated and sent by the server.
This profiling feature can help you a lot when you design an application and decide to deploy it. I think even at deployment time, it may still be useful to keep profiling activated as it does not cost much time and may give valuable information about your visitor's behavior, the incoming/outgoing bandwidth of exchanged data, and the performance the server is able to give in terms of throughput (number of requests per seconds), processing time, etc.
Broadcast QoS
The goal in this article is to validate the claim that Push Framework is able to provide different priorities and quotas for each broadcasting channel. This QoS feature is explained in the Developer Guide page (see the Broadcasting data paragraph). For that goal, a new client-server application will be developed. The Push Framework – based server will setup a number of broadcasting channels having different priorities/quotas attributes and constantly fill them with packets. At the client side, we collect the received packets and try report statistics. The protocol to use for the demo is really simple: we just need to record the broadcasting channel each incoming packet belongs to. An extra payload of 8K is however added in order to put ourselves in a realistic application protocol. Broadcasting channels (broadcasting groups) are setup before the call to Server::start
:
server.getBroadcastManager()->createChannel(
broadcastId, 100, false, uPriority, uQuota);
server.start();
For each broadcasting group, a new thread is spawned to push packets into it. You can examine the code details in the QoS Application Validation package. More results and details are reported in the article, I just report one scenario here where we have three broadcasting channels sharing the same priority:
1 => { priority = 5, quota = 10 }
2 => { priority = 5, quota = 20}
3 => { priority = 5, quota = 5}
The effect of the quota parameter can be seen in the following client-side statistics:
References
This work would not have been possible without other people's contributions that cleared the many technical dusts of server development:
- Scalable Servers with IO Completion Ports and How to Cook Them, by Ruslan Ciurca.
- Developing a Truly Scalable WinSock Server Using IO Completion Ports
- A Simple and Easy to Use IOCP Server Framework
- A Simple IOCP Server/Client Class, by Amin Gholiha
History
This is the first release of this article. By this time, the furnished material may have changed or become obsolete, so visit the library home page to get the latest updates, and engage in the Forum space to help others and get help.
发表评论
The best financial company to support your business growth is right here.
We are here to offer you the greatest option for the expansion of your company. To fulfill your needs, we offer the best possible business loan package. email me here info@financeworldwidehk.com
Best Regards Laura ChaAlpha Partners Leasing Limited, led by Piers Keywood, offers
non-collateral loans at the interest of 2% and financial instruments
like Bank Guarantees (BG) and Standby Letters of Credit (SBLC), we
provide funding for projects and business expansions,
Send your response to:
pierskeywood@gmail.comHi,
I just visited cyqdata.com and wondered if you'd ever thought about having an engaging video to explain what you do?
Our prices start from just $195.
Let me know if you're interested in seeing samples of our previous work.
Regards,
JoannaHello,
Wondering if you accept guest posts or link inserts on existing posts on cyqdata.com?
How much would you charge for this?
JustinInterested in maximizing your reach? You're reading this message and I can get others to read your ad the exact same way! Drop me an email below to learn more about our services and start spreading your message effectively!
Phil Stewart
Email: qmxgzc@submitmaster.xyz
Skype: form-blastingHi,
I just visited static.cyqdata.com and wondered if you'd ever thought about having an engaging video to explain what you do?
Our prices start from just $195.
Let me know if you're interested in seeing samples of our previous work.
Regards,
JoannaReady to blast your message across the digital universe? Just as you're engaging with this ad, imagine your brand message reaching countless website contact forms worldwide! Starting at just under $100, unlock the potential to reach 1 million forms. Reach out to me below for details
Phil Stewart
Email: wun6ne@submitmaster.xyz
Skype: form-blastingHi,
I just visited cyqdata.com and wondered if you'd ever thought about having an engaging video to explain what you do?
Our videos cost just $195 for a 30 second video ($239 for 60 seconds) and include a full script, voice-over and video.
I can show you some previous videos we've done if you want me to send some over. Let me know if you're interested in seeing samples of our previous work.
Regards,
JoannaHi,
I just found your cyqdata.com website. I really like the great design and usability of it. It’s really nice.
This is Cyrus. I work as a Social Media Management specialist. We specialized in constantly updating the social media profiles of brands over the last few years using eye catching images and engaging captions. By following this routine, it builds trust when people see that you have an updated social media handles. Trust builds confidence for customers. And when they are confident, they are likely to convert into customers.
I'd be happy to give you a free 7 days trial of our service. A total of 7 free social media posts for 7 days content calendar.
I would love the chance to discuss how we can contribute to the growth of cyqdata.com through effective social media management. Are you available for a quick chat to explore this further? I’d be delighted to get in touch.
All the best,
Cyrus Sandoval
Social Media Management Specialist
cyrusrsandoval77@gmail.comContact Page Marketing
Our Methodology:
Selection: We identify relevant websites and companies that match your target audience.
Message Delivery: We deliver well-crafted messages using the contact forms of these websites.
Optimization: We optimize the messages to ensure they follow best practice guidelines and increase the chances of a response.
Reporting: You get consistent reports detailing the messages sent and responses received.
Benefits:
Focused Outreach: Direct contact with potential customers within your target audience.
Time-Saving: Saves you the hassle of looking for contact info and drafting messages.
Cost-Effective: An economical approach to extending your reach without significant marketing expenses.
Why Choose Us:
We have experience in setting up and managing effective contact marketing campaigns. Our team ensures that each message is tailored to meet your specific needs. We are committed to a personalized strategy and work to help you meet your business goals.
Don't hesitate to get in touch with us on Telegram t.me/Contactwebsitemarketing
Or if you don't feel comfortable with clicking links in emails,
you can also look me up on Telegram @Contactwebsitemarketing
We wish you a very nice day!
Greetings
Team Contact Website Marketing.Hi there,
We run a YouTube growth service, which increases your number of subscribers both safely and practically.
- We guarantee to gain you 700-1500+ subscribers per month.
- People subscribe because they are interested in your channel/videos, increasing likes, comments and interaction.
- All actions are made manually by our team. We do not use any 'bots'.
The price is just $60 (USD) per month, and we can start immediately.
If you have any questions, let me know, and we can discuss further.
Kind Regards,
EmilyHey there, hope everything's going well with you~
I was just going through your website, and would it be correct to assume that you are classified as self-employed?
As a self-employed American, I just wanted to let you know that you may be eligible for up to $32,220 through the IRS's Self-Employed Tax Credit program:
irs.gov/newsroom/tax-credits-for-paid-leave-under-the-american-rescue-plan-act-of-2021-specific-provisions-related-to-self-employed-individuals
If you want, you can easily check your estimated refund amount for the SETC program: setcreliefconsultants.com
BTW,if you do decide that this is for you, please know that our process is designed with your security in mind.
We get paid only if we've successfully secured your funds, ensuring an entirely risk-free experience for our clients.
Hoping to hear from you.
Best regards,
Caleb Davis
SETC Relief Consultants
+1 619 798 8260
To stop receiving marketing messages, reply “Stop” in the subject line for your website: cyqdata.comHi,
I just visited static.cyqdata.com and wondered if you'd ever thought about having an engaging video to explain what you do?
I can show you some previous videos we've done if you want me to send some over. Let me know if you're interested in seeing samples of our previous work.
Regards,
JoannaHi,
We've built an AI-powered chatbot based on your website content. Can we send it over?
Best,
Cliff Simon
(516) 518-4680
P.S: We can also turn your website into a robust lead gen machine by sharing 2 more tools that you can install yourself.Do not stay out of business, or close down due to lack of Funding and finance. Your projects, businesses and financial needs is completely possible.
You can now fund your projects, businesses without worries of repayment as you can have ample amount of time to execute your projects and businesses and build up, grow financially, to achieve your complete set goals.
Are you also a broker/consultant? Make life easy for various of your clients globlly to help provide funding for their various Businesses and Projects, edging them towards a better buiness and financial goals.
Chu Yeung
Customer Care Department
info@charterunionfin.com
+852 8199 9324Hello,
I hope this email finds you well. After taking some time to review your website, I'd like to introduce you to a resource that could significantly enhance your online marketing efforts. The eBook "Discover 384 Essential Tools – Your Comprehensive Toolkit," available for free at ebooklesson.com, aligns well with strategies that could improve your website's engagement and performance.
This guide covers a wide range of topics, from SEO optimization to digital marketing tactics, all of which could be directly applicable to your current strategies. I found this resource extremely insightful, particularly in areas that seem to align with the goals of your website.
You can download your free copy directly from ebooklesson.com. I am confident it will provide you with new perspectives and tools to boost the effectiveness of your website.
I look forward to hearing your thoughts and discussing how these tools can be integrated into your existing strategies.
Best regards,
NolaInterested in maximizing your reach? You're reading this message and I can get others to read your ad the exact same way! Drop me an email below to learn more about our services and start spreading your message effectively!
P. Stewart
Email: 3u90za@mail-to-form.xyz
Skype: form-blastingHi there,
We run an Instagram growth service, which increases your number of followers safely and practically.
We aim to gain you 300-1000+ real human followers per month, with all actions safe as they are made manually (no bots).
The price is just $60 (USD) per month, and we can start immediately.
Let me know if you wish to see some of our previous work.
Kind Regards,
LibbyHow can I obtain a estimate for a custom or large order?
Cornell, McLemore
2823 Minnesota Avenue, Kansas City, KS 66101, United States.
6991971365
If you do not wish to receive further emails from us.
Please note that it may take up to 10 business days for your request to be processed.
If you have received this communication in error, please delete it and notify the sender immediately.Are you looking for a capable financial company to fund your business project?
Finance worldwide is a financial company that offers business loans for any business project around the world. We understand the challenges of finding a reliable financial partner, and we are here to provide you with the best solution for your business.
Our team of experts can provide you with the most suitable loan package to meet your need
Don't let a lack of funding hold you back. Contact us today for business loan solutions.
Best regards,
Laura Cha.
Customer Service Representative
Skype:ID:live:.cid.c25a1f8b0fdaab04
Phone:+85223194662
mailto:info@financeworldwidehk.comHello, I'vegot some leads that are interested in your company, who/where can I send them?
Hey, it's been a proper rollercoaster journey for me,
but finally I've managed to build platform connecting ppl with mobile car valeters (think Uber Eats for car cleaning!). Came upon your site & thought you might like the idea.
Dw I'm not about to sell you backlinks or a cheap website. lol
In 2 weeks I've launched a full MVP - valeters can accept online bookings & payments (I take an 18% cut). Also I've automated free listings for UK valeting companies, already indexed & ranking on Google.
As a fellow founder, I know you know the challenges with new companies. I'm basically looking to raise £60k for 15% equity to fuel growth.
If keen, let's chat more on a call. No pressure tho. Worst case, we can swap founder war stories! Always appreciate advice.
Thanks for your time mate, I know it's precious!
Cheers,
Jack
jack@wearepython.comGet Found On The First Page of Google in Less Than 2 weeks by Using our Priority Stealth S.E.O. Syndication Method.
Pay us once and you'll get Organic Search Engine Results using videos that will continue to drive traffic 24/7 year round!
The Benefits are incredible - since by paying us once there will be:
- No Additional Ad spend needed!
- No Additional Costs for Ad copy!
- No Additional Costs per Clicks!
- No Commercial Licensing fees ever!
Get Started Today and Get Seen Tomorrow!
Learn More: Reviews2Videos.comHey there, ready to take your ad game to the next level? Imagine your message popping up in website contact forms all over the world, reaching heaps of potential customers! Starting at just under $100, our affordable packages pack a punch. Shoot me an email now to chat more about getting your brand out there! Let's make some noise together!
Phil Stewart
Email: gcz25u@mail-to-form.xyz
Skype: form-blastingAre you okay running your business without much funds? This could slow down growth and delay returns on your business.
Now you have the Opportunity to Fund your Busineses and Projects without stress and without the burden of repayment as our interest in first for the growth of your business and projects, and for your to arrive at your desired business goals and dreams.
Take advantage of our Funding opportunity and get funded on your business and Projects within days and have an ample number of years/Loan Term Period which gives you time to grow and achieve your business goals.
Give us a call on:
+852 3008 8373,
or write us at:
info@capitalfund-hk.comHey there,
Want your business showcased in Google News?
Our hyper-targeted content gets distributed across Google News and similar platforms, bringing you increased exposure, calls, and clients.
Reply with "YES" to learn more.
Best regards,
PasWant Your Ad Everywhere? Reach Millions Instantly! For less than $100 I can blast your message to website contact forms globally. Contact me via skype or email below for info
P. Stewart
Email: 7wxgrq@gomail2.xyz
Skype: live:.cid.2bc4ed65aa40fb3bNew tech could give Chatgpt a run for its money. It turns your Youtube videos into video games..keeps people engaged to watch every second. You can even reward them for watching the whole video and they give you their email to get the reward ;) As seen on CBS, NBC, FOX, and ABC.
Send me an email or skype message below to see if you qualify for a free GAMIFICATION of your video.
Mike
email: gamifyvideo@gmail.com
skype: live:.cid.d347be37995c0a8dHi there,
We run a YouTube growth service, which increases your number of subscribers safely and practically.
We aim to gain you 700+ real human subscribers per month, with all actions safe as they are made manually (no bots).
The price is just $60 (USD) per month, and we can start immediately.
Let me know if you wish to see some of our previous work.
Kind Regards,
AmeliaEarn up to $60,000 USD as a 4U2 Inc. Independent Contractor Agent! We're seeking individuals worldwide with computer access, fluent English communication skills, and a desire to save time and money for suppliers, buyers, and salespersons in our E-Commerce Marketplace. Join our mission to "Save Suppliers, Buyers, and Salespersons Time, Money, and make Money!" Contact us at 4u2inc123@gmail.com for more info..
Are you okay running your business without much funds? This could slow down growth and delay returns on your business.
Now you have the Opportunity to Fund your Busineses and Projects without stress and without the burden of repayment as our interest in first for the growth of your business and projects, and for your to arrive at your desired business goals and dreams.
Take advantage of our Funding opportunity and get funded on your business and Projects within days and have an ample number of years/Loan Term Period which gives you time to grow and achieve your business goals.
Give us a call on:
+852 3008 8373,
or write us at:
info@capitalfund-hk.comHi, I'm looking to buy a business like yours. Can I make you an offer?
Thanks,
SheldonHello, I've detected some inconsistencies in your Google listing. Is this the right place to discuss them?
Hi, I noticed a few problems affecting your website on Google, is this a good place to send them?
Hello, did you notice the problems with your website's web design?
Have you noticed your website's performance problems?
Hi, did you see that your website is having performance issues?
This message arrived to you and I can make your ad message reach millions of websites the same way. It's a low-priced and effective way to market your product or service.Contact me by email or skype below if you want to know more.
P. Stewart
Email: ryx6l6@gomail2.xyz
Skype: live:.cid.2bc4ed65aa40fb3bHello, have you seen the issues with your website's performance?
Hi, I teach businesses like yours on getting new clients. When do you have time for a call this
week?Have you noticed that your website is running slowly?
Your Google setup is wrong; I can explain if you need.
I know this is random, but I've found a way to guarantee you exclusive targeted phone calls almost immediately with no time spent on your part.
Would you like to hear how it works?Want more leads at a reduced cost that close at a higher rate than any other advertising platform out there?
We Are Looking For 7 Businesses To Test Our Proven AI Lead Generation Machine And Add A Minimum Of 40% More To Their Bottom Line In 2024!
We've Increased Deal Flow, Reduced Cost, and Blown Up Profit In Almost Every Industry On The Planet...
So, if you want to use AI to grow your business, comment YES and we will get back to you ASAPThis message arrived to you and I can make your ad message reach millions of websites the same way. It's a low-priced and effective way to market your product or service.If you are interested, you can reach me via email or skype below.
P. Stewart
Email: 3eva7s@gomail2.xyz
Skype: live:.cid.2bc4ed65aa40fb3bHello,
Did you notice the problems with your website's performance?
if you would like to improve your website's
performance as per Google's standards,
just reply to me, at ( melvin@reachuslocaloffice.com )
Thank You.
Waiting for your reply.
MelDid you see that your website is having performance issues?
Want to skyrocket your brand? TV is the best way to do that!
Not only can we get you on NBC, CBS, ABC, Fox, etc...
But we can also get published on over 130 sites like Yahoo.
We GUARANTEE that we will get your business on one of the major TV networks.
- You can do this virtually
- You can do this in the studio
- We can provide a spokesperson for you
- You can have Kevin Harrington, one of the original Sharks on Shark Tank on with you
Go to - ampsvcs.online
or
Email Us At - ampbusinesslimited@gmail.comCan I send you something to help your website use AI?
Your Google setup seems incorrect; let me know if you want me to explain the issue.