前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Socket 简单通信

Socket 简单通信

作者头像
云雀叫了一整天
发布2019-09-29 16:57:57
7130
发布2019-09-29 16:57:57
举报
文章被收录于专栏:Hi, Python

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/weixin_40313634/article/details/80633155

功能:两个exe件实现信息交流。

优化方向:

1. 客户端断开连接后,服务器端应遵循四次握手,也要断开连接,重新绑定端口,继续监听等待下次连接。

2. 服务器或客户端均应可连续发送多条消息,而不是发送完毕后等待对方相应后才能继续发送。

3. 目前必须先启动服务器,再启动客户端。能否也可以先启动客户端,直接服务器启动后再建立连接,而不是直接断掉(当服务器未启动时)。

常用的 socket 接口函数:

1. int socket(int domain, int type, int protocol);

功能:根据指定的协议和类型,创建一个socket,并返回socket 的描述信息(类似创建文件后返回的文件指针)。

入参解释:

int domain :入参,指定socket 的协议族,常用的有 AF_INET(IPV4协议族)、AF_UNIX(UXIX 本地通信协议)等。 int type :指定socket 类型。常用的有 SOCK_STREAM(面向连接的,如发送邮件等)、SOCK_DGRAM(面向无连接的,如广播等)等等。

int protocol : 指定具体使用那个协议。常用的协议有,IPPROTO_TCP(TCP传输协议)、IPPTOTO_UDP(UDP传输协议)等等。

返回值: int socket :创建的socket 的描述符,唯一标识一个socket。

2. int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:给创建的socket 绑定对应的协议和端口。

入参解释:

int sockfd :入参,socket 描述符。

sockaddr *addr :入参,指向要绑定到socket 上的协议信息。不同协议,指针结构不同。

代码语言:javascript
复制
struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};   //  IPV4 指定的信息。

struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

socklen_t addrlen : 入参,对应的sockaddr 的地址长度。

返回值: int bind :绑定成功与失败(SOCKET_ERROR )。

3. int listen(int sockfd, int backlog);

功能:服务器监听绑定的的端口,等待客户端连接。

入参解释:

int sockfd :入参,socket 描述符。

int backlog :入参,socket 可以排队的最大连接个数。

返回值:

int listen: 有无(SOCKET_ERROR )连接。

4. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:客户机请求连接服务器。

入参解释:

int sockfd :入参,socket 描述符。

socketaddr *addr :入参,socket 的地址量。

socklen_t : 入参,socket 地址的长度。

返回值:

int conect: 客户机连接服务器成功与否。

5. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数解释:socket 描述符(入参),socket 的地址量(出参),socket 地址的长度(出参)。

6. int close(int fd);

功能:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

服务器端代码:

创建套接字 -> 绑定端口 -> 接受连接请求 -> 接受或发送数据 -> 断开连接。

代码语言:javascript
复制
#include "InitSock.h"   
#include <stdio.h>   
#include <iostream>  
using namespace std;  
CInitSock initSock;     // 初始化Winsock库   
  
int main()   
{   
    // 创建套节字:IPV4 协议族,面向无连接,TCP 协议。
    SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    
    if(sListen == INVALID_SOCKET)   
    {   
        printf("Failed socket() \n");   
        return 0;   
    }   
       
    // 填充套接字地址信息。
    sockaddr_in sin;   
    sin.sin_family = AF_INET;   
    sin.sin_port = htons(4567);  //1024 ~ 49151:普通用户注册的端口号  
    sin.sin_addr.S_un.S_addr = INADDR_ANY;   // INADDR_ANY:本机IP,如果是多网卡机器,表示多个IP 的集合。
       
    // 绑定套节字到本地主机地址   
    if(::bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)   
    {   
        printf("Failed bind() \n");   
        return 0;   
    }   
       
    // 监听端口,最多允许2个排队的socket。    
    if(::listen(sListen, 2) == SOCKET_ERROR)   
    {   
        printf("Failed listen() \n");   
        return 0;   
    }   
       
    // 循环接受客户的连接请求   
    sockaddr_in remoteAddr;    
    int nAddrLen = sizeof(remoteAddr);   
    SOCKET sClient = 0;   
    char szText[] = " TCP Server Demo! \r\n";   
    while(sClient==0)   
    {   
        // 接受一个新连接   
        //((SOCKADDR*)&remoteAddr)一个指向sockaddr_in结构的指针,用于获取对方地址  
        sClient = ::accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);   
        if(sClient == INVALID_SOCKET)   
        {   
            printf("Failed accept()");   
        }   
        else
        {
            printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));   
        } 
    }   
  
    while(TRUE)   
    {   
        // 向客户端发送数据   
        while( NULL != gets(szText) );   
            ::send(sClient, szText, strlen(szText), 0);   
           
        // 从客户端接收数据   
        char buff[256] ;   
        int nRecv = 0;   
        while( ::recv(sClient, buff, 256, 0) > 0)   
        {   
            buff[nRecv] = '\0';   
            printf(" Client :%s\n", buff);   
        }    
    }   
  
    // 关闭同客户端的连接   
    ::closesocket(sClient);   
           
    // 关闭监听套节字   
    ::closesocket(sListen);   
  
    return 0;   
}   

客户端代码:

代码语言:javascript
复制
#include "InitSock.h"   
#include <stdio.h>   
#include <iostream>   
using namespace std;  
CInitSock initSock;     // 初始化Winsock库   
  
int main()   
{   
    // 创建套节字   
    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   
    if(s == INVALID_SOCKET)   
    {   
        printf(" Failed socket() \n");   
        return 0;   
    }   
       
    // 也可以在这里调用bind函数绑定一个本地地址   
    // 否则系统将会自动安排   
       
    // 填写远程地址信息   
    sockaddr_in servAddr;    
    servAddr.sin_family = AF_INET;   
    servAddr.sin_port = htons(4567);   
    // 注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址   
    // 如果你的计算机没有联网,直接使用127.0.0.1即可   
    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");   
       
    if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)   
    {   
        printf(" Failed connect() \n");   
        return 0;   
    }   
       
    char buff[256];   
    char szText[256] ;   
       
    while(TRUE)   
    {   
        //从服务器端接收数据   
        int nRecv = ::recv(s, buff, 256, 0);   
        if(nRecv > 0)   
        {   
            buff[nRecv] = '\0';   
            printf("接收到数据:%s\n", buff);   
        }   
  
        // 向服务器端发送数据   
  
        gets(szText) ;   
        szText[255] = '\0';   
        ::send(s, szText, strlen(szText), 0) ;   
           
    }   
       
    // 关闭套节字   
    ::closesocket(s);   
    return 0;   
}   

封装的InitSock.h

代码语言:javascript
复制
#include <winsock2.h>   
#include <stdlib.h>    
#include <conio.h>    
#include <stdio.h>    
  
#pragma comment(lib, "WS2_32")  // 链接到WS2_32.lib   
  
class CInitSock        
{   
public:   
    CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)   
    {   
        // 初始化WS2_32.dll   
        WSADATA wsaData;   
        WORD sockVersion = MAKEWORD(minorVer, majorVer);   
        if(::WSAStartup(sockVersion, &wsaData) != 0)   
        {   
            exit(0);   
        }   
    }   
    ~CInitSock()   
    {      
        ::WSACleanup();    
    }   
};   

int socket(int domain, int type, int protocol);

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/06/09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档