在学习网络的时候,socket编程是一个重点。

socket有很多种概念: 在TCP/IP协议中,“IP地址+TCP或UDP端口号”可以唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。 

 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成 的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此用来描述网络连接的一 对一关系。

函数说明:

socket()——可用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源的函数。

wKiom1eYYaeAwFr_AACdT5hlF0U989.png-wh_50

connect()——用于建立与指定socket的连接。

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

wKiom1eYYjGhJjOIAABndvh5W6Y100.png-wh_50


listen()——创建一个套接口并监听申请的连接。

wKiom1eYYdzQfzqJAACrkfFm7m4225.png-wh_50

accept()——在一个套接口接受一个连接。

程序实现:

server:

   1、创建 socket;

        2、将socket 和 Server的IP、端口号进行绑定;

        3、设置为监听状态;

        4、每建立一个链接,就开启一个新的线程,在线程内部与对应的Client端进行通信。

        相关代码:  

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
 
static void usage(const char *proc )
{
    printf("Usage: %s [ip] [port]\n", proc);
}
 
void* thread_run(void *arg)
{
    printf("create a new thread\n");
    int fd = (int)arg;
    char buf[1024];
    while(1)
    {
        memset(buf, '\0', sizeof(buf));
        ssize_t _s = read(fd, buf, sizeof(buf) - 1 );
            if(_s > 0)
            {
                buf[_s - 1] = '\0';
                printf("client :# %s\n", buf);
                write(fd, buf, strlen(buf) );
                printf("please enter: ");
            }
        else if(_s == 0)
        {
            printf("client close...\n");
            break;
        }
        else
        {
            printf("read error...\n");
            break;
        }
    }
    return (void*)0;
}
 
int main(int argc, char *argv[] )
{
    if(argc != 3 )
    {
        usage(argv[0]);
        exit(1);
    }
 
 
    //1.CreateSocket
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(listen_sock < 0)
    {
        perror("socket");
        return 1;
    }
 
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[2]));  //argv[2]
    local.sin_addr.s_addr = inet_addr(argv[1]);
 
    //2.Bind
    if( bind(listen_sock, (struct sockaddr*)&local, sizeof(local) ) < 0)
    {
        perror("bind");
        return 2;
    }
 
    //3.Always Listen
    listen(listen_sock, 5);
 
    //4.Accept
    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);
    while(1)
    {
        int fd = accept(listen_sock, (struct sockaddr*)&peer, &len);
        if(fd < 0)
        {
            perror("accept");
            return 3;
        }
 
        printf("get a new link... socket -> %s : %d\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
 
        pthread_t id;
        pthread_create(&id, NULL, thread_run, (void*)fd);
        pthread_detach(id);
 
    }
    return 0;
}

         client:

   1、创建Socket;

        2、连接;

        3、通信。

        相关代码:

 #include <stdio.h>
#include <sys/socket.h>
#include <syspes.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
 
static void usage(const char *proc )
{
    printf("Usage: %s [ip] [port]\n", proc);
}
 
int main(int argc, char *argv[])
{
    if(argc != 3 )
    {
        usage(argv[0]);
        exit(1);
    }
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket");
        return 2;
    }
    struct sockaddr_in remote;
    remote.sin_family = AF_INET;
    remote.sin_port = htons(atoi(argv[2]));
    remote.sin_addr.s_addr = inet_addr(argv[1]);
 
    if( connect(sock, (struct sockaddr*)&remote, sizeof(remote) ) < 0)
    {
        perror("connect");
        return 3;
    }
 
    char buf[1024];
    while(1)
    {
        printf("Please Enter: ");
        fflush(stdout);
        ssize_t _s = read(0, buf, sizeof(buf) - 1);
 
        if(_s > 0)
        {
            buf[_s - 1] = '\0';
            write(sock, buf, strlen(buf));
            _s = read(sock, buf, sizeof(buf));
            if( _s > 0)
            {
                buf[_s] = '\0';
                printf("%s\n", buf);
            }
        }
    }
    return 0;
}

注意:client端的端口号不需要像server端那样固定以方便连接,不需要绑定,因此client的端口号是由内核自动分配的。

        结果展示:

wKiom1eYZkiBeYBqAAAarYnhVQ4130.png

wKioL1eYZkmDJMSbAAAsp2pel_4231.png