1 一个简单的 Socket 程序

server.cpp

#include <netinet/in.h>
#include <memory.h>
#include <unistd.h>
#include <iostream>

int main()
{
    int nListenSocket = ::socket(AF_INET, SOCK_STREAM, 0);

    std::cout << nListenSocket << std::endl;

    if(-1 == nListenSocket)
    {
    std::cout << "socket error" << std::endl;
    return 0;
    }

    sockaddr_in ServerAddress;
    memset(&ServerAddress, 0, sizeof(sockaddr_in));
    ServerAddress.sin_family = AF_INET;
    ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    ServerAddress.sin_port = htons(4000);

    if(::bind(nListenSocket, (sockaddr *)&ServerAddress, sizeof(sockaddr_in)) == -1)
    {
    std::cout << "bind error" << std::endl;
    ::close(nListenSocket);
    return 0;
    }

    if(::listen(nListenSocket, 23) == -1)
    {
    std::cout << "listen error" << std::endl;
    ::close(nListenSocket);
    return 0;
    }

    sockaddr_in ClientAddress;
    socklen_t LengthOfClientAddress = sizeof(sockaddr_in);
    int nConnectedSocket = ::accept(nListenSocket, (sockaddr *)&ClientAddress, &LengthOfClientAddress);
    if(-1 == nConnectedSocket)
    {
    std::cout << "accept error" << std::endl;
    ::close(nListenSocket);
    return 0;
    }

    ::write(nConnectedSocket, "Hello World\n", 13);

    ::close(nConnectedSocket);
    ::close(nListenSocket);

    return 0;
}

client.cpp

#include <sys/socket.h>
#include <netinet/in.h>
#include <memory.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>

int main()
{
    int nClientSocket = ::socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == nClientSocket)
    {
    std::cout << "socket error" << std::endl;
    return 0;
    }

    sockaddr_in ServerAddress;
    memset(&ServerAddress, 0, sizeof(sockaddr_in));
    ServerAddress.sin_family = AF_INET;
    if(::inet_pton(AF_INET, "127.0.0.1", &ServerAddress.sin_addr) != 1)
    {
    std::cout << "inet_pton error" << std::endl;
    return 0;
    }

    ServerAddress.sin_port = htons(4000);

    if(::connect(nClientSocket, (sockaddr*)&ServerAddress, sizeof(ServerAddress)) == -1)
    {
    std::cout << "connect error" << std::endl;
    return 0;
    }

    char buf[13];
    ::read(nClientSocket, buf, 13);

    std::cout << buf << std::endl;

    ::close(nClientSocket);

    return 0;
}

编译并运行

服务器端:

g++ -o server server.cpp -g
./server
3

客户端端:

g++ -o client client.cpp -g
./client
Hello World

可以看到客户端成功与服务器建立连接,服务器给客户端发送了“Hello World”。

2 Socket 函数的相关内容

2.1 Socket 函数

Socket 函数的头文件为:<sys/socket.h>

Socket 函数的原型为:int socket(int family, int type, int protocol);

Socket 函数的返回值称为套接字,这个套接字是一个非负整数值。若 Socket 函数出错,将返回-1。

其中 family 表示协议族或者协议域。有值:

协议名称 协议名称
AF_INET IPv4 协议 2
AF_INET6 IPv6 协议 10
AF_LOCAL Unix 域协议 1
AF_ROUTE 路由器套接口 16
AF_KEY 密钥套接口 15

其中 type 表示套接口的类型。有值:

接口类型 接口名称
SOCK_STREAM 字节流套接口 1
SOCK_DGRAM 数据报套接口 2
SOCK_SEQPACKET 有序分组套接口 5
SOCK_RAW 原始套接口 3
SOCK_PACKET 数据链路套接口 10

其中 protocol 是传输协议的类型。有值:

传输协议的类型 传输协议类型名称
IPPROTO_TCP TCP 传输协议 6
IPPROTO_UDP UDP 传输协议 7
IPPROTO_SCTP SCTP 传输协议 132

在 protocol 中,可以取值为 0,让系统根据 family 和 type 的值自动选取合适的 protocol 值。

此行代码表明 socket 连接使用的是 Ipv4 协议,套接口的类型为字节流套接口。

2.2 套接字的地址结构

Ipv4 套接口地址结构为:

在编程中,首先定义一个套接口接口对象,然后使用 memet 函数将内存区域清 0。之后对其结构体字段进行赋值。

服务端代码:

客户端代码:

2.3 bind 函数

bind 函数用于将套接口地址信息与套接口绑定在一起。
函数原型为:int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

其中参数的含义为:

参数 参数含义
sockfd socket 函数的返回值
myaddr 套接口地址信息,包括 family、端口、IP
addrlen 套接口地址结构大小
类型 socklen_t unsigned int
返回值 成功为 0,出错为-1

TCP 服务器若使用 bind 函数,则将服务器绑定在一个已经设置好的端口上。如果不是用 bind 函数,则将在调用 listen 函数/connect 函数中,自动给服务器分配一个端口。

2.4 listen 函数

listen 函数将一个未连接的套接口转换为一个被动套接口。

其函数原型为:int listen(int sockfd, int backlog); 第一个 sockfd 参数表示成功创建的 TCP 套接字,第二个 backlog 参数表示 TCP 处理连接的队列长度。

listen 函数在运行中要维护两个队列:未完成连接队列和已完成连接队列。

2.5 accept 函数

accept 函数将从已完成连接的队列中取出下一个已完成的连接。如果已完成连接的队列为空,则将进入睡眠状态。

其函数原型为:int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 若接收错误,则返回-1。

其中参数的含义为:

参数 参数的含义
sockfd socket 函数的返回值
cliaddr 当 accept 函数返回时,内核将从已完成连接队列中,取出一个连接;并将该连接的客户端信息(协议族、IP、Port),保存在 cliaddr 指向的结构体中
addrlen 调用 accept 前,*addrlen 的值为 cliaddr 实际所指的套接口地址结构的长度;accept 返回时,内核填充*addrlen,该值为确切地客户套接口地址结构长度

3.6 connect 函数

connect 函数的作用是使客户端向服务器端发起 TCP 连接。

其函数原型为:int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); 连接成功则返回 0,连接出错则返回-1。
其中参数的含义为:

参数 参数的含义
sockfd socket 函数的返回值
servaddr 服务器的地址信息,包括 IP,Port,协议族
addrlen 服务器套接口地址结构的长度

如果连接失败,则套接字将不可以再使用,必须关闭。

3.7 数据收发函数

数据收发函数有 read、write、send、recv、close。read 函数将缓冲区的数据读出,write 函数将数据发送到缓冲区。send 函数将数据发出,recv 函数接收数据。close 函数负责结束数据传输。

0
Posted in c++

#include <iostream>
#include <queue>
using namespace std;

int main()
{
    // 创建一个队列
    queue<int> q;

    // 向队列中插入元素
    q.push(1);
    q.push(2);
    q.push(3);

    // 访问队列中元素个数
    cout<<q.size()<<endl;

    // 访问队首元素
    cout<<q.front()<<endl;

    // 访问队尾元素
    cout<<q.back()<<endl;

    // 出队
    while(!q.empty()){
        // 打印队首元素
        cout<<q.front()<<endl;
        q.pop();
    }

    return 0;
}
0
Posted in c++, DataStructure

#include <iostream>
#include <stack>
using namespace std;

int main()
{
    // 创建一个堆栈
    stack<int> s;

    // 向栈中插入元素
    s.push(1);
    s.push(2);
    s.push(3);

    // 将栈中元素依次出栈
    while(!s.empty()){
        cout<<s.top()<<endl;
        s.pop();
    }
    return 0;
}
0
Posted in c++, DataStructure

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

struct node{
    int data;
    struct node *next;
};

// head pointer holds the address of the starting node of the linked list
struct node *head;

int createLinkedList(){
    struct node *newnode,*temp;
    newnode = (struct node*)malloc(sizeof(struct node));
    printf("\nenter the data into the linked list:");
    scanf("%d", &newnode->data);
    newnode->next=NULL;
    if(head == NULL){
        head = newnode;
        return 1;
    }
    else{
        temp = head;
        while(temp->next!=NULL)
        {
            temp = temp->next;
        }
        temp->next=newnode;
        return 1;
    }
}
void display()
{
    struct node *temp;
    temp = head;
    if(head!=NULL){
        for(temp = head; temp!=NULL; temp = temp->next){
            printf("%d\n",temp->data);
        }
    }
    else{
        printf("The list is empty...");
    }

}
int main()
{
    int ch;
    head = NULL;
    do{
        printf("\n1.create linked list");
        printf("\n2.display linked list");
        printf("\n3.exit");
        printf("\n4.enter your choice:");
        scanf("%d", &ch);
        switch(ch)
        {
        case 1:
            createLinkedList();
            break;
        case 2:
            display();
            break;
        case 3:
            exit(1);
            break;
        default:
            printf("\nwrong entry please continue try...");

        }
    }while(ch!=3);
}
0
Posted in c++, DataStructure