简单socket()编程

Posted 思考与实践并行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单socket()编程相关的知识,希望对你有一定的参考价值。

客户端:

1、socket( int af, int type, int protocol)

socket()函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源。如果协议protocol未指定(等于0),则使用缺省的连接方式。 对于使用一给定地址族的某一特定套接口,只支持一种协议。但地址族可设为AF_UNSPEC(未指定),这样的话协议参数就要指定了。协议号特定于进行通讯的“通讯域”。

SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP。 SOCK_STREAM类型的套接口为全双向的字节流。对于流类套接口,在接收或发送数据前必需处于已连接状态。用connect()调用建立与另一套接口的连接,连接成功后,即可用send()和recv()传送数据。当会话结束后,调用close()。带外数据根据规定用send()和recv()来接收。 实现SOCK_STREAM类型套接口的通讯协议保证数据不会丢失也不会重复。

如果终端协议有缓冲区空间,且数据不能在一定时间成功发送,则认为连接中断,其后续的调用也将以WSAETIMEOUT错误返回。

SOCK_DGRAM 支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务,为Internet地址族使用UDP。 

2、int connect(int s, const struct sockaddr * name, int namelen)
用于创建与指定外部端口的连接。s参数指定一个未连接的数据报或流类套接口。如套接口未被捆绑,则系统赋给本地关联一个唯一的值,且设置套接口为已捆绑。对于流类套接口(SOCK_STREAM类型),利用名字来与一个远程主机建立连接,一旦套接口调用成功返回,它就能收发数据了。对于数据报类套接口(SOCK_DGRAM类型),则设置成一个缺省的目的地址,并用它来进行后续的send()与recv()调用。

3、int send( SOCKET s, const char FAR *buf, int len, int flags );  

send就仅仅把buf中的数据copy到剩余空间里,注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里 

#include <stdio.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>    //加了该头文件,seraddr.sin_addr.s_addr    = inet_addr(SEVERIP);则无warning

#define SEVERIP "192.168.31.103"
#define SEVERPORT 9003

int sockfd    = -1;
int ret        = -1;


char sendbuf[100];

struct sockaddr_in cliaddr = {0};
struct sockaddr_in seraddr = {0};

int main()
{
    //create socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);//地址族:AF_INET表示IPV4;
                                            //服务:SOCK_STREAM
                                            //协议缺省:0
    if(sockfd < 0)
    {
        perror("socket");
        return -1;        
    }
    printf("sockfd = %d\n",sockfd);

    

    //initiate a connection on a socket
    seraddr.sin_family        = AF_INET;
    seraddr.sin_port        = htons(SEVERPORT);
    seraddr.sin_addr.s_addr    = inet_addr(SEVERIP);

    ret = connect(sockfd, (const struct sockaddr*)&seraddr, sizeof(seraddr));
    if(ret < 0)
    {
        perror("connect");
        return -1;
    }
    
    printf("connect result,ret = %d.\n", ret);
    
    //communication---send content
    //strcpy(sendbuf, "hello world");
    printf("***************************************\n");
    while(1)
    {
        printf("Please input you content to send:");
        memset(sendbuf, 0, sizeof(sendbuf));
        scanf("%s",sendbuf);
        ret = send(sockfd, sendbuf, strlen(sendbuf),0);
        printf("***************************************\n");    
    }
    return 0;
}

 客户端

1、bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)

2、int listen(SOCKET sockfd, int backlog);
 backlog 连接请求队列(queue of pending connections)
 listen在套接字函数中表示让一个套接字处于监听到来的连接请求的状态

3、 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
本函数从sockfd的等待连接队列中抽取第一个连接,创建一个与sockfd同类的新的套接口并返回句柄。如果队列中无等待连接,且套接口为阻塞方式,则accept()阻塞调用进程直至新的连接出现。如果套接口为非阻塞方式且队列中无等待连接,则accept()返回一错误代码。已接受连接的套接口不能用于接受新的连接,原套接口仍保持开放。

4、int recv( _In_ SOCKET s, _Out_ char *buf, _In_ int len, _In_ int flags)
 同步Socket的recv函数的执行流程。当应用程序调用recv函数时:(1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;(2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的)

#include <stdio.h>
#include <sys/types.h>      
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#define SERVER_IP        "192.168.31.103 "
#define SERVER_PORT        9003
#define backlog            100


struct sockaddr_in seraddr = {0};
struct sockaddr_in cliaddr = {0};

int socketfd = -1, clifd = -1;
int ret = -1;

char recvbuf[100];

socklen_t len;

int main()
{
    //Create socket
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if(socketfd < 0)
    {
        perror("Fail to creat socket");
        return -1;        
    }
    printf("socketfd= %d.\n",socketfd);
    
    //Assigning a name to a socket
    seraddr.sin_family    = AF_INET;
    seraddr.sin_port    = htons(SERVER_PORT);
    seraddr.sin_addr.s_addr    = inet_addr(SERVER_IP);

    ret = bind(socketfd, (const struct sockaddr*)(&seraddr), sizeof(seraddr));
    if(ret < 0)
    {
        perror("Fail to bind");
        return -1;
    }
    
    //Listen
    ret = listen(socketfd, backlog);
    if(ret < 0)
    {
        perror("Listen");
        return -1;        
    }
    
    //Wait for client 
    clifd = accept(socketfd, (struct sockaddr*)(&cliaddr), &len);
    if(clifd < 0)
    {
        perror("Wait for client");
        return -1;
    }
    printf("Wait for client successful,fd = %d.\n",clifd);
    
    //communication---Receive content
    printf("***************************************\n");

    
    while(1)
    {
        ret = recv(clifd, recvbuf, sizeof(recvbuf), 0);
        printf("The receive substance is [%s].\n", recvbuf);
        memset(recvbuf, 0, sizeof(recvbuf));    
    }

    
    return 0;
}


 

 

以上是关于简单socket()编程的主要内容,如果未能解决你的问题,请参考以下文章

python,socket网络编程,最简单的server端和client端代码

Socket编程的简单实现

socket网络编程:在简单套接字基础上加上通信循环(代码完善)

C语言 UDP socket 简单客户端 编程,急

Linux:TCP Socket编程(代码实战)

Linux:TCP Socket编程(代码实战)