Socket编程详解

1  计算机网络基础

1.1 OSI参考模型(略)

1.2 TCP/IP协议

传输控制协议/网际协议,TCP/IP将网络分为四层,从高往低一次为应用层-》传输层-》网络层-》数据链路层。其中,传输层协议包括TCP,UDP;网络层协议包括IP、ARP等;

2  套接字编程基础

2.1  套接字

套接字是网络编程的基础,最初由加利福尼亚大学为UNIX开发的网络通信编程接口,为了在WINDOWS 操作系统上使用,微软与第三方厂商共同制定了一套标准,Winsock.。

套接字实际上是一个指向传输提供者的句柄,Winsock中通过该句柄实现网络通信与管理。

可以理解为实现网络通信和管理的操作接口。

2.1.1 套接字类型

根据套接字作用不同,分为三类:原始套接字、流式套接字和数据包套接字。

原始套接字(SOCK_RAW):能够使程序人员对底层的网络机制进行控制,接收的数据包头中含有IP头。

流式套接字(SOCK_STREAM):提供了双向、有序、可靠的数据传输服务,在通信前需要双方建立连接,TCP协议采用了该套接字。

数据包套接字(SOCK_DGRAM):与流式套接字相对应,提供双向数据流,但是不能保证数据传输的可靠性、有序性和无重复性。UDP协议采用了该套接字。

//2.2 套接字I/O模型

(暂缺)
2.3 套接字函数

为了使用套接字进行网络程序开发,Windows操作系统提供了一组套接字函数,使用这些函数,可以实现功能强大的网络编程。常用可分为三大类:初始化库函数(WSAStartup()、WSACleanup())、通信时使用函数(socket()、bind()、listen()、accept()、closesocket()、connect()、recv()、send()、select()、ioctlsocket())和地址转换函数(htons()、htonl()、inet_addr())。

其中,WSAStartup()用于初始化动态链接库函数,WSACleanup()用于释放动态链接库初始化时分配的资源。

注:套接字函数通常封装在Ws2_32.dll动态链接库中,其头文件Winsock2.h提供了套接字函数的原型,库文件Ws2_32.lib提供了Ws2_32.dll文件的输出节,在使用套接字函数前,需包含头文件 ,并链接Ws2_32.lib。

#include <winsock2.h>

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

3  网络编程步骤

实现网络间通信,需要一个服务器端和一个客户端。这两者之间的具体实现有点不同,大体步骤为:

3.1 服务器端

(1)创建套接字:socket()创建套接字,指明传输协议

例如:
sListen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
//sListen代表返回的套接字

//AF_INET为IPV4地址家族 
//SOCK_STREAM为套接字类型 //IPPROTO_TCP指明传输协议

(2)构建本地地址信息

//构建本地地址信息
    saServer.sin_family = AF_INET; //地址家族
    saServer.sin_port = htons(SERVER_PORT); //注意转化为网络字节序
    saServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用INADDR_ANY 指示任意地址  

(3)bind()函数把一个地址族中的特定地址赋给socket。

(4)监听:lidten()

(5)等待连接:accept()

3.2 客户端

(1)创建套接字

(2)构建服务器地址

(3)连接服务器connect()

4  实例

下面通过一个简单的客户端/服务器端程序,讲解通信编程的具体实现:

//服务器端
// Server.cpp : 定义控制台应用程序的入口点。
//TCP测试程序的服务器端程序
#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER_PORT 5208 //侦听端口  

int _tmain(int argc, _TCHAR* argv[])
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int ret, nLeft, length;
    SOCKET sListen, sServer; //侦听套接字,连接套接字
    struct sockaddr_in saServer, saClient; //地址信息
    char *ptr;//用于遍历信息的指针
    //WinSock初始化
    wVersionRequested=MAKEWORD(2, 2); //希望使用的WinSock DLL 的版本
    ret=WSAStartup(wVersionRequested, &wsaData);
    if(ret!=0)
    {
        printf("WSAStartup() failed!\n");
        //return 0;
    }
    //创建Socket,使用TCP协议
    sListen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sListen == INVALID_SOCKET)
    {
        WSACleanup();
        printf("socket() faild!\n");
        //return 0;
    }
    //构建本地地址信息
    saServer.sin_family = AF_INET; //地址家族
    saServer.sin_port = htons(SERVER_PORT); //注意转化为网络字节序
    saServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用INADDR_ANY 指示任意地址  

    //绑定
    ret = bind(sListen, (struct sockaddr *)&saServer, sizeof(saServer));
    if (ret == SOCKET_ERROR)
    {
        printf("bind() faild! code:%d\n", WSAGetLastError());
        closesocket(sListen); //关闭套接字
        WSACleanup();
        //return 0;
    }  

    //侦听连接请求
    ret = listen(sListen, 5);
    if (ret == SOCKET_ERROR)
    {
        printf("listen() faild! code:%d\n", WSAGetLastError());
        closesocket(sListen); //关闭套接字
        //return 0;
    }  

    printf("Waiting for client connecting!\n");
    printf("Tips: Ctrl+c to quit!\n");  

    //阻塞等待接受客户端连接
    while(1)//循环监听客户端,永远不停止
    {
        length = sizeof(saClient);
        sServer = accept(sListen, (struct sockaddr *)&saClient, &length);
        if (sServer == INVALID_SOCKET)
        {
            printf("accept() faild! code:%d\n", WSAGetLastError());
            closesocket(sListen); //关闭套接字
            WSACleanup();
            return 0;
        }    

        char sendMessage[]="\nhello client";  //发送信息给客户端
        send(sServer,sendMessage,strlen(sendMessage)+1,0);  

        char receiveMessage[5000];
        nLeft = sizeof(receiveMessage);
        ptr = (char *)&receiveMessage;
        while(nLeft>0)
        {
            //接收数据
            ret = recv(sServer, ptr, 5000, 0);    //非负,成功;-1,失败
            if (ret == SOCKET_ERROR)
            {
                printf("recv() failed!\n");
                return 0;
            }
            if (ret == 0) //客户端已经关闭连接
            {
                printf("Client has closed the connection\n");
                break;
            }
            nLeft -= ret;
            ptr += ret;
        }
        printf("receive message:%s\n", receiveMessage);//打印我们接收到的消息。  

    }
  //  closesocket(sListen);
  //  closesocket(sServer);
  //  WSACleanup();
    return 0;
}  
//TCP测试程序的客户端程序
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER_PORT 5208 //侦听端口  

int _tmain(int argc, _TCHAR* argv[])
{
    WORD wVersionRequested;
    WSADATA wsaData;            //WSADATA为Windows套接字结构体
    int ret;
    SOCKET sClient; //连接套接字
    struct sockaddr_in saServer; //服务器地址信息
    char *ptr;  

    BOOL fSuccess = TRUE;  

    //---------------------------------------------------------------
    //WinSock初始化
    //---------------------------------------------------------------
    wVersionRequested = MAKEWORD(2, 2); //希望使用的WinSock DLL的版本
    ret = WSAStartup(wVersionRequested, &wsaData);  //加载套接字库
    if(ret!=0)
    {
        printf("WSAStartup() failed!\n");
        //return 0;
    }
    //确认WinSock DLL支持版本2.2
    if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2)
    {
        WSACleanup();   //释放为该程序分配的资源,终止对winsock动态库的使用
        printf("Invalid WinSock version!\n");
        //return 0;
    }  

    //创建Socket,使用TCP协议
    sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sClient == INVALID_SOCKET)
    {
        WSACleanup();
        printf("socket() failed!\n");
        //return 0;
    }  

    //构建服务器地址信息
    saServer.sin_family = AF_INET; //地址家族
    saServer.sin_port = htons(SERVER_PORT); //注意转化为网络节序
    saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  

    //连接服务器
    ret = connect(sClient, (struct sockaddr *)&saServer, sizeof(saServer));
    if (ret == SOCKET_ERROR)
    {
        printf("connect() failed!\n");
        closesocket(sClient); //关闭套接字
        WSACleanup();
        //return 0;
    }  

    char sendMessage[]="hahaha!!!";
    ret = send (sClient, (char *)&sendMessage, sizeof(sendMessage), 0);
    if (ret == SOCKET_ERROR)
    {
        printf("send() failed!\n");
    }
    else
        printf("client info has been sent!");
    char recvBuf[100];
    recv(sClient,recvBuf,100,0);
    printf("%s\n",recvBuf);  

    closesocket(sClient); //关闭套接字
    WSACleanup();
    //getchar();  没啥用,让你最后在显示终端可以输入一串字符,但是不能发送
    //return 0;
}
  
时间: 2024-10-19 08:10:17

Socket编程详解的相关文章

Linux的SOCKET编程详解(转)

Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如 UNIX BSD有:管道(pipe).命名管道(named pipe)软中断信号(signal) UNIX system V有:消息(message).共享存储区(shared memory)和信号量(semaphore)等. 他们都仅限于用在本机进程之间通信.网间进

Java开发之Socket编程详解

本文从3个方面对Socket编程进行详解: 一,网络编程中两个主要的问题 二,两类传输协议:TCP:UDP 三,基于Socket的java网络编程 一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机.而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要

[转]Linux的SOCKET编程详解

From : http://blog.csdn.net/hguisu/article/details/7445768 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如 UNIX BSD有:管道(pipe).命名管道(named pipe)软中断信号(signal) UNIX system V有:消息(message).共享存储区(shared mem

Linux的SOCKET编程详解

1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如 UNIX BSD有:管道(pipe).命名管道(named pipe)软中断信号(signal) UNIX system V有:消息(message).共享存储区(shared memory)和信号量(semaphore)等. 他们都仅限于用在本机进程之间通信.网间进程通信要解决的是不同主机进程间的相

java网络socket编程详解

7.2 面向套接字编程    我们已经通过了解Socket的接口,知其所以然,下面我们就将通过具体的案例,来熟悉Socket的具体工作方式 7.2.1使用套接字实现基于TCP协议的服务器和客户机程序    依据TCP协议,在C/S架构的通讯过程中,客户端和服务器的Socket动作如下: 客户端: 1.用服务器的IP地址和端口号实例化Socket对象. 2.调用connect方法,连接到服务器上. 3.将发送到服务器的IO流填充到IO对象里,比如BufferedReader/PrintWriter

PHP Socket 编程详解

最近在做的项目有一项需要耗时任务在后台运行的功能,虽然PHP并不是非常适合做常驻后台的守护进程,但是由于项目主要代码都是基于PHP实现,如果运行在后台的守护进程改换别的语言会非常不方便.所以不可避免会涉及到Web端和Daemon部分的通信,Socket是一个不错的方式. Socket是什么 socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意思.通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄.在Internet上的主机一般运行了多个服务软件,

socket原理详解

1.什么是socket 我们知道进程通信的方法有管道.命名管道.信号.消息队列.共享内存.信号量,这些方法都要求通信的两个进程位于同一个主机.但是如果通信双方不在同一个主机又该如何进行通信呢?在计算机网络中我们就学过了tcp/ip协议族,其实使用tcp/ip协议族就能达到我们想要的效果,如下图(图片来源于<tcp/ip协议详解卷一>第一章1.3) .  图一 各协议所处层次 当然,这样做固然是可以的,但是,当我们使用不同的协议进行通信时就得使用不同的接口,还得处理不同协议的各种细节,这就增加了

Socket模型详解(转)

Socket模型详解(转) Socket模型详解 两种I/O模式 一.选择模型 二.异步选择 三.事件选择 四.重叠I/O模型 五.完成端口模型 五种I/O模型的比较 两种I/O模式 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权.这种模式使用起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误

MFC下CSocket编程详解

MFC下CSocket编程详解 分类: C/C++2008-03-13 09:01 34465人阅读 评论(34) 收藏 举报 mfc编程socket服务器socketsstream MFC下CSocket编程详解: 1. 常用的函数和注意事项(详细的函数接口说明请查看MSDN): CSocket::Create 初始化(一般写服务器程序都不要用为好,用下面的 CSocket::Socket 初始化) CSocket::Socket初始化 CSocket::SetSockOpt 设置socket