使用socket写代码主要是要看自己的需求是什么。 如果通信时,内容很重要就要使TCP方式。 如果用户数太多,可能就要使用UDP方式了。 在TCP模式下,最简单的方式就是这样的,使阻塞方式: 服务端: 1.初始化socket环境,创建socket 2.梆定一个端口 3.开始监听 4.接收客户端 5.接收到客户端之后,使用这个socket来与这个客户通信

#include "stdAfx.h" #include <winsock2.h> #include <mswsock.h> #include <iostream>

using namespace std;

#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib")

DWORD IniSOCKDLL() { WORD wVersionRequested; WSADATA wsaData; int err=0; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); return err; }

int main(int argc, char* argv[]) { cout<<"程序开始"<<endl; IniSOCKDLL(); SOCKET ss=WSASocket(AF_INET,   SOCK_STREAM,   0,   NULL,   0,   NULL); SOCKADDR_IN addr; int len; addr.sin_family=AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(1002); len=sizeof(addr); bind(ss , (PSOCKADDR)&addr , len); listen(ss,5); SOCKET sc=accept(ss,(PSOCKADDR)&addr,&len); char buff[1024]; ZeroMemory(buff,1024); recv(sc,buff,1024,0); cout<<buff<<endl; ZeroMemory(buff,1024); memcpy(buff,"123",3); send(sc,buff,3,0); closesocket(sc); closesocket(ss); return 0; }

客户端: 1.初始化socket环境,创建socket 2.连接服务端 3.开启一个线程来接收数据 4.使用send直接发数据包

#include "stdAfx.h" #include <winsock2.h> #include <mswsock.h> #include <iostream>

using namespace std;

#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib")

DWORD IniSOCKDLL() { WORD wVersionRequested; WSADATA wsaData; int err=0; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); return err; }

int main(int argc, char* argv[]) { IniSOCKDLL(); SOCKET sc=WSASocket(AF_INET,   SOCK_STREAM,   0,   NULL,   0,   NULL); SOCKADDR_IN addr; int len; addr.sin_family=AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(1002); len=sizeof(addr); connect(sc, (struct sockaddr *)&addr, len); char buff[1024]; ZeroMemory(buff,1024); memcpy(buff,"123",3); send(sc,buff,3,0);

recv(sc,buff,1024,0); cout<<buff<<endl;

closesocket(sc); return 0; }

由这个我们可以做一个这样的模型: 为每个阻塞函数开一个线程,让它来处理。 这就要留意退出的时候把这一些线程给关闭。

当然TCP方式的模型还有事件选择模型。 就是把所有的网络事件和我们的一个程序里定义的事件梆定。 这个有它的好处,可能可以让我们更好的写一个线程来管理 接收与发送。 现在来讲一下一个完成端口模型。

完成端口   一个完成端口其实就是一个通知队列,由操作系统把已经完成的重叠I/O请求的通知 放入其中。当某项I/O操作一旦完成,某个可以对该操作结果进行处理的工作者线程 就会收到一则通知。而套接字在被创建后,可以在任何时候与某个完成端口进行关 联。 步骤: 1、创建一个空的完成端口; 2、得到本地机器的CPU个数; 3、开启CPU*2个工作线程(又名线程池),全部都在等待完成端口的完成包; 4、创建TCP的监听socket,使用事件邦定,创建监听线程; 5、当有人连接进入的时候,将Client socket保存到一个我们自己定义的关键键,     并把它与我们创建的完成端口关联; 6、使用WSARecv和WSASend函数投递一些请求,这是使用重叠I/O的方式; 7、重复5~6;

注:1、重叠I/O的方式中,接收与发送数据包的时候,一定要进行投递请求这是    它们这个体系结构的特点    当然,在完成端口方式中,不是直接使用的WSARecv和WSASend函数进行请求    的投递的。而是使用的ReadFile,Write的方式   2、完成端口使用了系统内部的一些模型,所以我们只要按照一定的顺序调用就    可以完成了。   3、完成端口是使用在这样的情况下,有成千上万的用户连接的时候,它能够    保证性能不会降低。

#include <winsock2.h> #include <windows.h> #include <stdio.h>

#define PORT 5150 #define DATA_BUFSIZE 8192

//关键项 typedef struct {    OVERLAPPED Overlapped;    WSABUF DataBuf;    CHAR Buffer[DATA_BUFSIZE];    DWORD BytesSEND;    DWORD BytesRECV; } PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;

typedef struct {    SOCKET Socket; } PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

void main(void) {    SOCKADDR_IN InternetAddr;    SOCKET Listen;    SOCKET Accept;    HANDLE CompletionPort;    SYSTEM_INFO SystemInfo;    LPPER_HANDLE_DATA PerHandleData;    LPPER_IO_OPERATION_DATA PerIoData;    int i;    DWORD RecvBytes;    DWORD Flags;    DWORD ThreadID;    WSADATA wsaData;    DWORD Ret;

if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)    {       printf("WSAStartup failed with error %d\n", Ret);       return;    }

//打开一个空的完成端口

if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)    {       printf( "CreateIoCompletionPort failed with error: %d\n", GetLastError());       return;    }

// Determine how many processors are on the system.

GetSystemInfo(&SystemInfo);

// 开启cpu个数的2倍个的线程

for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)    {       HANDLE ThreadHandle;

// Create a server worker thread and pass the completion port to the thread.

if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,          0, &ThreadID)) == NULL)       {          printf("CreateThread() failed with error %d\n", GetLastError());          return;       }

// Close the thread handle       CloseHandle(ThreadHandle);    }

//打开一个服务器socket

if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,       WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)    {       printf("WSASocket() failed with error %d\n", WSAGetLastError());       return;    }

InternetAddr.sin_family = AF_INET;    InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);    InternetAddr.sin_port = htons(PORT);

if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)    {       printf("bind() failed with error %d\n", WSAGetLastError());       return;    }

if (listen(Listen, 5) == SOCKET_ERROR)    {       printf("listen() failed with error %d\n", WSAGetLastError());       return;    }

//开始接收从客户端来的连接

while(TRUE)    {       if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)       {          printf("WSAAccept() failed with error %d\n", WSAGetLastError());          return;       }

// 创建一个关键项用于保存这个客户端的信息,用户接收发送的重叠结构,       // 还有使用到的缓冲区       if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,          sizeof(PER_HANDLE_DATA))) == NULL)       {          printf("GlobalAlloc() failed with error %d\n", GetLastError());          return;       }

// Associate the accepted socket with the original completion port.

printf("Socket number %d connected\n", Accept);       PerHandleData->Socket = Accept;

//与我们的创建的那个完成端口关联起来,将关键项也与指定的一个完成端口关联       if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,          0) == NULL)       {          printf("CreateIoCompletionPort failed with error %d\n", GetLastError());          return;       }

// 投递一次接收,由于接收都需要使用这个函数来投递一个接收的准备

if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR,          sizeof(PER_IO_OPERATION_DATA))) == NULL)       {          printf("GlobalAlloc() failed with error %d\n", GetLastError());          return;       }

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));       PerIoData->BytesSEND = 0;       PerIoData->BytesRECV = 0;       PerIoData->DataBuf.len = DATA_BUFSIZE;       PerIoData->DataBuf.buf = PerIoData->Buffer;

Flags = 0;       if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,          &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)       {          if (WSAGetLastError() != ERROR_IO_PENDING)          {             printf("WSARecv() failed with error %d\n", WSAGetLastError());             return;          }       }    } } //工作线程 DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID) {    HANDLE CompletionPort = (HANDLE) CompletionPortID;    DWORD BytesTransferred;    LPOVERLAPPED Overlapped;    LPPER_HANDLE_DATA PerHandleData;    LPPER_IO_OPERATION_DATA PerIoData;    DWORD SendBytes, RecvBytes;    DWORD Flags;       while(TRUE)    {       //完成端口有消息来了       if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,          (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)       {          printf("GetQueuedCompletionStatus failed with error %d\n", GetLastError());          return 0;       }

//是不是有人退出了

if (BytesTransferred == 0)       {          printf("Closing socket %d\n", PerHandleData->Socket);

if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)          {             printf("closesocket() failed with error %d\n", WSAGetLastError());             return 0;          }

GlobalFree(PerHandleData);          GlobalFree(PerIoData);          continue;       }

//

if (PerIoData->BytesRECV == 0)       {          PerIoData->BytesRECV = BytesTransferred;          PerIoData->BytesSEND = 0;       }       else       {          PerIoData->BytesSEND += BytesTransferred;       }

if (PerIoData->BytesRECV > PerIoData->BytesSEND)       {

// Post another WSASend() request.          // Since WSASend() is not gauranteed to send all of the bytes requested,          // continue posting WSASend() calls until all received bytes are sent.

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;          PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;

if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,             &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)          {             if (WSAGetLastError() != ERROR_IO_PENDING)             {                printf("WSASend() failed with error %d\n", WSAGetLastError());                return 0;             }          }       }       else       {          PerIoData->BytesRECV = 0;

// Now that there are no more bytes to send post another WSARecv() request.

Flags = 0;          ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.len = DATA_BUFSIZE;          PerIoData->DataBuf.buf = PerIoData->Buffer;

if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,             &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)          {             if (WSAGetLastError() != ERROR_IO_PENDING)             {                printf("WSARecv() failed with error %d\n", WSAGetLastError());                return 0;             }          }       }    } }

原文:http://www.cnblogs.com/cnLiou/articles/202150.html

C++Socket编程总结 [转]的更多相关文章

  1. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  2. java socket编程(li)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以 ...

  3. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  4. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  5. Linux下的C Socket编程 -- 获取对方IP地址

    Linux下的C Socket编程(二) 获取域名对应的IP地址 经过上面的讨论,如果我们想要连接到远程的服务器,我们需要知道对方的IP地址,系统函数gethostbyname便能够实现这个目的.它能 ...

  6. Linux下的C Socket编程 -- 简介与client端的处理

    Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...

  7. python网络编程-socket编程

     一.服务端和客户端 BS架构 (腾讯通软件:server+client) CS架构 (web网站) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 二.OSI七层 ...

  8. Socket编程实践(2) Socket API 与 简单例程

    在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程.该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端. socket()函 ...

  9. Socket编程实践(1) 基本概念

    1. 什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口.TCP/IP协议的底层部分已经被内核实现了,而应用层是用户需要实现的,这部分程序工作在用户空间.用户空间的程序需要通 ...

  10. [转]C语言SOCKET编程指南

    1.介绍 Socket编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措?等 ...

随机推荐

  1. Javascript 与正则表达式

    一.正则表达式(regular expression简称res) 二.元字符及其在正则表达式上下文中的行为 三.正则表达式的常用方法 四.与正则表达式有关的字符串对象的方法 五.常用的正则表达式的操作 ...

  2. Facebook Messenger的后台架构是什么样的?

    后台的架构是由前台的需求决定的.做 mobile app 的需求跟做 web app 是不一样的,比如 mobile app 对实时性的要求比较强(移动用户都没耐性),移动设备网络不稳定(要能做到断点 ...

  3. 9.12 其他样式;JS

    Display 显示block和隐藏none,不占位置Visbility 显示visible和隐藏hidden,占位置Overflow 超出范围 hidden隐藏透明圆角 Js脚本语言(JavaScr ...

  4. Linux 下 Oracle 内核参数优化

    数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...

  5. 电脑中的Bois是什么

    电脑中的Bois是什么 BOIS= Basic Input/Output System,基本输入输出系统,全称是ROM-BOIS,是只读存储器基本输入/输出系统的简写,它实际是一组被固化到电脑中,为电 ...

  6. parted命令详解

    parted命令详解   用法:parted [选项]... [设备 [命令 [参数]...]...]   将带有“参数”的命令应用于“设备”.如果没有给出“命令”,则以交互模式运行.   帮助选项: ...

  7. windows 修改hosts 脚本

    @echo off echo "请注意你的杀毒软件提示,一定要允许" echo. & pause @del C:\Windows\System32\drivers\etc\ ...

  8. 10月21上午PHP基础

    新建的php文件必须要放在wamp安装目录下的www文件夹里.如果拿到别的地方,php无法运行,将显示错误. <?php?> //嵌入php的方式 <?php //嵌入php方式的开 ...

  9. Python学习笔记——基本语法

    1.程序输出——print语句 >>> myString = 'Hello World!' >>> print myString Hello World! > ...

  10. MySQL学习笔记——多表连接和子查询

    多表连接查询 # 返回的是两张表的乘积 SELECT * FROM tb_emp,tb_dept SELECT COUNT(*) FROM tb_emp,tb_dept # 标准写法,每个数据库都能这 ...