Linux网络编程

网络编程中的函数调用成功一般返回大于等于0的值,失败一般返回-1 

一.客户端 

1.socket()

在Linux中进行网络编程无论是服务器还是客户端第一步都是创建一个socket,socket()函数返回的是一个文件描述符(类似一个id)

man文档中写着是创建一个端点用来comunication

domain参数用于表示使用哪一个协议族,百分之99都是IPv4

 

 2.connect()

man文档中的描述是将一个socket连接初始化

第一个参数刚刚用socket()创建出来的文件描述符,第二个参数指向struct sockaddr结构体的指针,第三个参数结构体的大小

struct sockaddr_in c_addr;
c_addr.sin_family = AF_INET;            //表示IPv4地址族
c_addr.sin_port = htons(port);
inet_aton(in_ip.c_str(),&c_addr.sin_addr);
      
if(::connect(socket_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1)
{
    ::close(socket_fd); 
    socket_fd=-1; 
    return false;
}

htons()函数将port从主机字节序转换成网络字节序(大端字节序)

以及c_str()将in_ip字符串装换成c风格的字符串

inet_aton()将字符串形式的ip转换赋值给c_addr.sin_addr

inet_ntoa()与inet_aton()相反

3.send()

string msg="你好世界!";
send(socket_fd,msg.data(),msg.size(),0);

4.recv()

 

string buffer;
int maxsize=128;
buffer.resize(maxsize);
recv(socket_fd,&buffer[0],maxsize,0);//最后一个参数一般为0

flags 参数允许你指定一些特殊的选项,这些选项可以改变 recv 的行为,不需要的话一般设置为0。

5.close()

close(fd);成功返回0

二.服务端

1.bind()

struct sockaddr_in s_addr;
s_addr.sin_family=AF_INET;//ipv4地址族
s_addr.sin_port=htons(port);//转化成网络字节序
inet_aton(in_ip.c_str(),&s_addr.sin_addr);//将ip写入结构体

bind(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//绑定用于通信的ip和端口

 2.listen()

(1)sockfd:这是一个由 socket() 函数返回的套接字文件描述符。这个套接字已经通过 bind() 函数绑定了地址,并准备开始监听连接请求。

(2)backlog:这个参数指定了内核应该为相应套接字排队的最大连接个数。请注意,这并不是一个限制客户端连接数的硬限制,而是一个在服务器进程开始处理之前可以排队的未完成连接请求的数量。通常,这个值被设置为 5 到 10 之间,但也可以根据实际情况进行调整。

listen(socket_fd,10);

 3.accept()

如果 accept() 调用时监听套接字的等待连接队列中没有等待的连接,并且套接字没有被设置为非阻塞(non-blocking)模式,那么 accept() 会阻塞调用线程,直到有一个连接请求到来。

函数原型  ->  int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

struct sockaddr_in c_addr;
socklen_t c_size=sizeof(struct sockaddr_in);
int c_fd=accept(socket_fd,(struct sockaddr *)&c_addr,&c_size);

(1)如果 accept() 函数调用成功,它会返回一个新的套接字文件描述符,这个套接字与客户端建立了一个连接,可以用于发送和接收数据。

(2)如果调用失败,则返回 -1,并设置全局变量 errno 以指示错误原因

(3)accept() 函数返回的新套接字与原始的监听套接字是不同的。监听套接字继续监听新的连接请求,而新的套接字则用于与特定的客户端进行通信

(4)在多进程或多线程编程中,accept() 函数可以用于实现并发服务器。

4.rec()、send()

注意一下服务端用来接收和发送的文件描述符是accep()函数返回的,并不是socket()函数创建的

 

三.两个用类封装过的网络编程demo

1.客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>

using namespace std;

class client
{
public:
    int socket_fd;
    string ip;
    unsigned short port;
    client():socket_fd(-1){}
    bool connect(string in_ip,unsigned short in_port)
    {
        if(socket_fd!=-1)return false;
        ip=in_ip,port=in_port;
        struct sockaddr_in c_addr;

        socket_fd = socket(AF_INET, SOCK_STREAM,0);
        if(socket_fd == -1){
            return false;
        }
        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(port);
        inet_aton(in_ip.c_str(),&c_addr.sin_addr);

        if(::connect(socket_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1)
        {
            ::close(socket_fd);
            socket_fd=-1;
            return false;
        }
        return true;
    }
    bool send(string msg)
	{
        if(socket_fd==-1)return false;
        int x=::send(socket_fd,msg.data(),msg.size(),0);
        if(x<0)return false;
        return true;
    }
    bool recv(string &buffer,int maxsize)
    {
        if(socket_fd==-1)return false;
        buffer.clear();
        buffer.resize(maxsize);
        int realsize=::recv(socket_fd,&buffer[0],maxsize,0);
        if(realsize<0)
    	{
            buffer.clear();
            std::cerr << "接收失败!错误代码: " << errno << ", 错误信息: " << strerror(errno) << std::endl;
            return false;
        }

        buffer.resize(realsize);
        return true;
    }
    bool close()
    {
        if(socket_fd==-1)return false;
        ::close(socket_fd);
        socket_fd=-1;
        return true;
    }
    ~client(){close();}
};
int main(int argc,char *argv[])
{
    if(argc<3)
    {
        cout<<"参数不够!\n";
        return 0;
	}
    client myclient;
    string readBuf;
    if(myclient.connect(argv[1],atoi(argv[2]))==false)
    {
        cout<<"连接失败!";
        return 0;
    }
    for(int i=0;i<10;i++)
    {
        string sendmsg="来自客户端的消息";
        if(!myclient.send(sendmsg))cout<<"发送失败!";


        if(!myclient.recv(readBuf,128))cout<<"接收失败!";
        else cout<<readBuf<<i<<"\n";
        sleep(1);
    }
    return 0;
}

2.服务端

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <cerrno>

using namespace std;

class server
{
public:
    int socket_fd;
    int client_fd;
    string ip;
    unsigned short port;

    server():socket_fd(-1){}
    bool connect(string in_ip,unsigned short port)
    {
        if(socket_fd!=-1)return false;
        socket_fd=socket(AF_INET,SOCK_STREAM,0);
        if(socket_fd==-1)
        {
            return false;
        }
        struct sockaddr_in s_addr;
		s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(port);
        inet_aton(in_ip.c_str(),&s_addr.sin_addr);

        bind(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        listen(socket_fd,10);

        struct sockaddr_in c_addr;
        socklen_t c_size=sizeof(struct sockaddr_in);
        int c_fd=accept(socket_fd,(struct sockaddr *)&c_addr,&c_size);
        if(c_fd==-1)
        {
            perror("accept failed!");
            ::close(socket_fd);
            socket_fd=-1;
            return false;
        }
        client_fd=c_fd;
        return true;
    }
    bool send(string msg)
    {
        if(socket_fd==-1)return false;
        int x=::send(client_fd,msg.data(),msg.size(),0);
        if(x<0)return false;
        return true;
    }
    bool recv(string &msg,int maxsize)
    {
		if(socket_fd==-1)return false;
        msg.clear();
        msg.resize(maxsize);

        int x=::recv(client_fd,&msg[0],maxsize,0);
        if(x<0)
        {
            msg.clear();
            cout<<"接收失败!";
            std::cerr << "接收失败!错误代码: " << errno << ", 错误信息: " << strerror(errno) << std::endl;
            return false;
        }
        msg.resize(x);
        return true;
    }
    bool close()
	{
        if(socket_fd==-1)return false;
        ::close(socket_fd);
        socket_fd=-1;
    }
    ~server(){close();}
};
int main(int argc,char *argv[])
{
	if(argc<3)
    {
        cout<<"参数不够!";
        return 0;
    }
    server server_socket;
    if(server_socket.connect(argv[1],atoi(argv[2]))==false)
    {
        cout<<"连接失败!";
        return 0;
    }
    string msg;
    for(int i=0;i<10;i++)
    {
        if(!server_socket.recv(msg,128))cout<<"接收失败!\n";
        else cout<<msg<<i<<"\n";

        string sendmsg="来自服务端的消息";
        if(!server_socket.send(sendmsg))cout<<"发送失败!\n";
        sleep(1);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值