unity中socket通信_C++中的TCP socket通信

以前学的是Java中的socket通信,现在由于实习原因,更多接触C++了,今天来讲讲C++中的socket通信。

socket的基本操作:

1,socket()函数

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

socket()用于创建一个socket的套接字,它唯一标识一个socket。后续的操作都有用到这个套接字,把它作为参数,通过它来进行一些读写操作。

socket()的参数:

domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL...

type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET等等

protocol:指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等。当protocol为0时,会自动选择type类型对应的默认协议。

使用:int server_socket = socket(PF_INET, SOCK_STREAM, 0);---返回socket套接字

2,bind()函数

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

bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

bind()的参数:

sockfd:即socket套接字,它是通过socket()函数创建了,唯一标识一个socket.

addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。

addrlen:对应的是地址的长度。

使用:bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))---返回0即表示成功

3,listen()、connect()函数

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

服务器:int listen(int sockfd, int backlog);

客户端:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket套接字,第二个参数为相应socket可以排队的最大连接个数。

connect函数的第一个参数即为客户端的socket套接字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。

4,accept()函数

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

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。

accept函数返回的是已连接的socket套接字。

socket中TCP建立连接的三次握手:

tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

客户端向服务器发送一个SYN J

服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1

客户端再想服务器发一个确认ACK K+1

aabbb890a742d6a242047691343a7167.png
socket中TCP建立连接的三次握手

当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

socket中TCP释放连接的四次握手:

0dc9dfeeeaba63ab115c0a1bf58ff117.png
socket中TCP释放连接的四次握手

某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;

另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;接收到这个FIN的源发送端TCP对它进行确认。这样每个方向上都有一个FIN和ACK。

TCP socket通信过程:

服务端:

1,创建socket套接字:

SOCKET sockSrv =socket(AF_INET, SOCK_STREAM,0);

2,套接字分配地址信息(端口和ip):

int retVal =bind(sockSrv,(LPSOCKADDR)&addrSrv,sizeof(SOCKADDR_IN));

3,监听socket:listen(sockSrv,10)

4,接受客户端的连接请求:

SOCKET sockConn =accept(sockSrv,(SOCKADDR *)&addrClient,&len);

客户端:

1,创建套接字:

SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);

2,向服务端发出连接请求:

connect(sockClient, (struct sockaddr*)&addrSrv, sizeof(addrSrv))

以上,客户端和服务端连接成功后,就可以通信了。

b701edb3e867acd3c6fac8ca7a3e0baa.png

最后,socket通信还可以跨系统哟~

参考代码:

Linux上的TCP socket 通信:

服务端:

#define _WINSOCK_DEPRECATED_NO_WARNINGS

客户端:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>

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

void main()
{
    //加载套接字
    WSADATA wsaData;
    char buff[1024];
    memset(buff, 0, sizeof(buff));

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock");
        return;
    }

    SOCKADDR_IN addrSrv;
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(5099);
    addrSrv.sin_addr.S_un.S_addr = inet_addr("10.130.42.91");

    //创建套接字
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    if (SOCKET_ERROR == sockClient){
        printf("Socket() error:%d", WSAGetLastError());
        return;
    }

    //向服务器发出连接请求
    if (connect(sockClient, (struct  sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET){
        printf("Connect failed:%d", WSAGetLastError());
        return;
    }
    else
    {
        //接收数据
        recv(sockClient, buff, sizeof(buff), 0);
        printf("%sn", buff);
    }

    //发送数据
    char *buffSend = "hello, this is a Client....";
    send(sockClient, buffSend, strlen(buffSend) + 1, 0);
    printf("%d", strlen(buffSend) + 1);

    //关闭套接字
    closesocket(sockClient);
    WSACleanup();
    system("pause");
}

Linux上的TCP socket 通信:

服务端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
 
int main(int argc, char *argv[])
{
    int server_sockfd;//服务器端套接字
    int client_sockfd;//客户端套接字
    int len;
    struct sockaddr_in my_addr;   //服务器网络地址结构体
    struct sockaddr_in remote_addr; //客户端网络地址结构体
    int sin_size;
    char buf[BUFSIZ];  //数据传送的缓冲区
    memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
    my_addr.sin_family=AF_INET; //设置为IP通信
    my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
    my_addr.sin_port=htons(8000); //服务器端口号
    
    /*创建服务器端套接字--IPv4协议,面向连接通信,TCP协议*/
    if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
    {  
        perror("socket error");
        return 1;
    }
 
 
    /*将套接字绑定到服务器的网络地址上*/
    if(bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
    {
        perror("bind error");
        return 1;
    }
    
    /*监听连接请求--监听队列长度为5*/
    if(listen(server_sockfd,5)<0)
    {
        perror("listen error");
        return 1;
    };
    
    sin_size=sizeof(struct sockaddr_in);
    
    /*等待客户端连接请求到达*/
    if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
    {
        perror("accept error");
        return 1;
    }
    printf("accept client %s/n",inet_ntoa(remote_addr.sin_addr));
    len=send(client_sockfd,"Welcome to my server/n",21,0);//发送欢迎信息
    
    /*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/
    while((len=recv(client_sockfd,buf,BUFSIZ,0))>0)
    {
        buf[len]='0';
        printf("%s/n",buf);
        if(send(client_sockfd,buf,len,0)<0)
        {
            perror("write error");
            return 1;
        }
    }
 
 
    /*关闭套接字*/
    close(client_sockfd);
    close(server_sockfd);
    
    return 0;
}

客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
 
int main(int argc, char *argv[])
{
    int client_sockfd;
    int len;
    struct sockaddr_in remote_addr; //服务器端网络地址结构体
    char buf[BUFSIZ];  //数据传送的缓冲区
    memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零
    remote_addr.sin_family=AF_INET; //设置为IP通信
    remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器IP地址
    remote_addr.sin_port=htons(8000); //服务器端口号
    
    /*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/
    if((client_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
    {
        perror("socket error");
        return 1;
    }
    
    /*将套接字绑定到服务器的网络地址上*/
    if(connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr))<0)
    {
        perror("connect error");
        return 1;
    }
    printf("connected to server/n");
    len=recv(client_sockfd,buf,BUFSIZ,0);//接收服务器端信息
        buf[len]='0';
    printf("%s",buf); //打印服务器端信息
    
    /*循环的发送接收信息并打印接收信息(可以按需发送)--recv返回接收到的字节数,send返回发送的字节数*/
    while(1)
    {
        printf("Enter string to send:");
        scanf("%s",buf);
        if(!strcmp(buf,"quit")
            break;
        len=send(client_sockfd,buf,strlen(buf),0);
        len=recv(client_sockfd,buf,BUFSIZ,0);
        buf[len]='/0';
        printf("received:%s/n",buf);
    }
    
    /*关闭套接字*/
    close(client_sockfd);
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值