c socket

  • 1.socke分类

  • 2.基本操作函数

  • 3.c实现的网络聊天程序

套接字(socket) 是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。

c socket_第1张图片

1. socke分类

  • 1.1流式套接字
    它提供了一种可靠的、面向连接的双向数据传输服务,实现了数据无差错、无重复的发送。在TCP/IP协议簇中,使用TCP协议来实现字节流的传输。
  • 1.2数据报套接字
    它提供了一种无连接、不可靠的双向数据传输服务。数据包以独立的形式被发送,并且保留了记录边界,不提供可靠性保证。在TCP/IP协议簇中,使用UDP协议来实现数据报套接字。
  • 1.3原始套接字
    该套接字允许对较低层协议(如IP或ICMP)进行直接访问。

2. 基本操作函数

  • 创建套接字 socket()
    socket()函数调用的格式:
    socket(int af,int type,int protocol);
    参数af指定套接字使用的协议族
    type参数指定所需的通信类型。包括数据流数据报原始类型
    参数protocol说明该套接字使用的协议族中的特定协议。如果调用者不希望特别指定使用的协议,则置为0,使用默认的连接模式。
  • bind():绑定本地地址
    一个套接字用socket()创建后,它其实还没有与任何特定的本地或目的地址相关联
  • connect():将套接字连接到目的地址
    初始创建的套接字并未与任何外地目的地址关联。客户机可以调用connect()为套接字绑定一个永久的目的地址,将它置于已连接状态。
  • listen():设置等待连接状态
    对于一个服务器的程序,当申请到套接字,并调用bind()与本地地址绑定后,就应该等待某个客户机的程序来要求连接。listen()就是把一个套接字设置为这种状态的函数。
  • accept():接受连接请求
    服务器进程使用系统调用socket,bind和listen创建一个套接字,将它绑定到知名的端口,并指定连接请求的队列长度。然后,服务器调用accept进入等待状态,直到到达一个连接请求。
  • send()/recv()和sendto()/recvfrom()
    发送和接收数据。

3. c实现的网络聊天程序]

  • client进程编码
# 
    #pragma comment(lib,"ws2_32.lib")
    #include
    #include 
    #include  
    #define DATA_BUFFER 1024
    int main(int argc, char * argv[]){
    WSADATA wsaData;
    SOCKET sClient;
    int i =5;
    int iSend;
    int iPort = 5050;
    int iLen;
    char buf[DATA_BUFFER]; 
    struct sockaddr_in ser; 

    if(argc<2) 
        {
        printf("Usage: client [server IP address]\n"); 
        return -1;
        }
    memset(buf,0,sizeof(buf)); 
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {
        printf("Failed to load Winsock.\n"); 
        return -1;
        }

    ser.sin_family = AF_INET; 
    ser.sin_port = htons(iPort); 
    ser.sin_addr.s_addr = inet_addr(argv[1]);
    sClient = socket(AF_INET,SOCK_STREAM,0); 
    if(sClient == INVALID_SOCKET)
        {
        printf("socket() Failed: %d\n",WSAGetLastError());
        return -1;
        }

    if(connect(sClient,(struct sockaddr *)&ser,sizeof(ser)) == INVALID_SOCKET)
        {
        printf("connect() Failed: %d\n",WSAGetLastError());
        return -1;
        }
    else
        {
        while(i-->0)
        {   
            iLen = recv(sClient,buf,sizeof(buf),0); 
        if(iLen == 0)
            return -1;
        else if(iLen == SOCKET_ERROR)
            {
            printf("recv() Failed: %d\n",WSAGetLastError());
            return -1;
            }

            else
            printf("recv() data from server: %s\n",buf); // 输出接收数据
            printf("输入:");
            scanf("%s",buf); 
            iSend = send(sClient,buf,sizeof(buf),0); 

            if(iSend == SOCKET_ERROR) //错误处理
            {
            printf("send() Failed: %d\n",WSAGetLastError());
            break;
            }
        else if(iSend == 0)
                {
                break;
                }
            else
                {
                printf("send() byte: %d\n",iSend); //输出发送成功字节数
                }
        }
        }   
    closesocket(sClient); //关闭 socket
    WSACleanup();
    return 0;}
  • sever进程编码

    #include 
    #include 
    #include 
    #define DEFAULT_PORT 5050 //服务端默认端口
    int main(){
    int iPort = DEFAULT_PORT;  //输入端口号
    WSADATA wsaData;  //数据结构,用来存储被 WSAStartup()调用返回的socket 
    
    SOCKET sListen,sAccept;    // 
    int i =5;
    int iLen; //客户机地址长度
    int iSend; //发送数据长度
    char buf[] = "I am a server"; //要发送给客户的信息
    
    struct sockaddr_in ser,cli; //服务器和客户的地址
    
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {   
        printf("Failed to load Winsock.\n"); //Winsock 初始化错误
        return -1;
        }
        
    sListen = socket(AF_INET,SOCK_STREAM,0); //创建服务器端套接字 ,SOCK_STREAM面向连接 
    
    if(sListen == INVALID_SOCKET)         // INVALID_SOCKET= -1 
        {
        printf("socket() Failed: %d\n",WSAGetLastError()); //返回上次发生的网络错误  ,INVALID_SOCKET =-1
        return -1;
        }
    
    //以下初始化服务器端地址
    ser.sin_family = AF_INET; //使用 IP 地址族
    ser.sin_port = htons(iPort); //主机序端口号转换为网络字节序端口号
    ser.sin_addr.s_addr = htonl(INADDR_ANY); //主机序 IP 地址转换为网络字节序主机地址 INADDR_ANY :0x00000000
    
    //使用系统指定的 IP 地址 INADDR_ANY
    if(bind(sListen,(LPSOCKADDR)&ser,sizeof(ser)) == SOCKET_ERROR) //套接定与地址的绑定
        {
        printf("bind() Failed: %d\n",WSAGetLastError());
        return -1;
        }

    if(listen(sListen,5) == SOCKET_ERROR) //进入监听状态,listen的第二个参数为可以排队的最大连接个数   SOCKET_ERROR =-1 
        {
        printf("lisiten() Failed: %d\n",WSAGetLastError());
        return -1;
        } 
    iLen = sizeof(cli); //初始化客户端地址长度参数  16B
    
    while(1) //进入循环等待客户的连接请求
        {
        sAccept = accept(sListen,(struct sockaddr *)&cli,&iLen); //第一个参数:服务器的socket描述字,2: 指针,用于返回客户端的协议地址,3:协议地址的长度 
        
        if(sAccept == INVALID_SOCKET)
            {
            printf("accept() Failed: %d\n",WSAGetLastError());
            return -1;
            }
        
        printf("Accepted client IP:[%s],port:[%d]\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
        //输出客户端 IP 地址和端口号
        while(i-->0)
        {
        
        iSend = send(sAccept,buf,sizeof(buf),0); //1指定发送端套接字描述符2存放应用程序要发送数据的缓冲区3发送的数据的字节数 4一般置0 
        if(iSend == SOCKET_ERROR) //错误处理
            {
            printf("send() Failed: %d\n",WSAGetLastError());
            break;
            }
        else if(iSend == 0)
                {
                break;
                }
            else
                {
                printf("send() byte: %d\n",iSend); //输出发送成功字节数
                }
        
        iLen = recv(sAccept,buf,sizeof(buf),0); 
        if(iLen == 0)
            return -1;
        else if(iLen == SOCKET_ERROR)
            {
            printf("recv() Failed: %d\n",WSAGetLastError());
            return -1;
            }
            else
            printf("recv() data from server: %s\n",buf); // 输出接收数据

        printf("输入:");
        scanf("%s",buf); 
        }
        closesocket(sAccept);
        }
    closesocket(sListen); //关闭 socket
    WSACleanup(); //输出发送成功字节数
    return 0;}
  • 输出结果

    客户端

    c socket_第2张图片

服务器端
c socket_第3张图片

你可能感兴趣的:(c socket)