socket编程,对于多进程,多线程的使用是必不可少的,因此写一篇博客来记录一下子。

// 多进程的头文件
#include <unistd.h>
// 多线程的头文件
#include <pthread.h>

多进程在此不做讲解了,直接看多线程

解释区

创建源(监听)套接字

#include <sys/socket.h>
// AF_INET:本机使用IPv4协议族
// SOCK_STREAM:TCP传输协议
// 0:protocol
lfd = socket(AF_INET, SOCK_STREAM, 0);

绑定自己的地址

// 服务器的地址和端口信息
ct sockaddr_in 
{
    sa_family_t    sin_family;  //地址族
    uint16_t       sin_port;    //16位的TCP/UDP 端口号
    struct in_addr sin_addr;    //32位IP地址
    char           sin_zero;    //不使用
};
struct sockaddr_in server_addr, client_addr;
server_addr.sin_family = AF_INET;
// IP和port要进入网络中进行一起传输,因此要转换成网络字节序
// hton--->主机字节序转换成网络字节序
// s--->表示16位
server_addr.sin_port = htons(SERVER_PORT);
// inet_addr:把字符串转换成二进制格式
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// bind方法
// 使用(struct sockaddr*)是因为他只能接收sockaddr的格式数据
bind(lfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

允许连接的主机个数

listen(lfd, 8);

进入循环,表示接收不同的主机

获得目标(通信)套接字

// client_addr表示的是主机的服务器和地址
// 此处获得了一个针对一个主机的通信套接字cfd
cfd = accept(lfd, (struct sockaddr*)&client_addr, &client_addr_len);

把客户端信息和服务端的目的套接字进行封装并进行初始化和实例化

typedef struct {
    struct sockaddr_in caddr;       // client:ip+port
    int confd;      // server <-socket-> client
}addr;
addr addr1;
addr1.caddr = client_addr;
addr1.confd = cfd;

初始化和创建一个线程

pthread_t thread;
pthread_create(&thread, NULL, func, (void*)&addr1);

分离当前线程

// 就不用主线程去结合
/* 在此注意pthread_join和pthread_detach的区别
* join是主线程等待子线程执行完再执行
* detach是子线程与主线程分离联系
*/
pthread_detach(pthread_self());

对参数进行拷贝和强转

addr* p = (addr*)arg;

对于某一个用户,会发送多条消息,因此设置死循环

while(1) {
	// bzero:将一个数组清零
    bzero(buf, 100);
    // 读取客户端传输的内容
    read(p->confd, buf, 100);
    if (!strncmp(buf, "quit", 4)) break;
    printf("[%s][%d]:%s\n", inet_ntoa(p->caddr.sin_addr),ntohs(p->caddr.sin_port), buf);
    }

关闭该通信套接字

close(p->confd);

printf内容

// inet_ntoa:将32位网络字节序二进制地址转换成点分十进制的字符串
// ntohs:port:网络字节序->主机字节序
printf("[%s][%d]client exit\n", inet_ntoa(p->caddr.sin_addr), ntohs(p->caddr.sin_port));

代码区

// 2020.03.06
// for liuhao
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <iostream>
#include <pthread.h>
#include <time.h>

#define SERVER_PORT 6666
using std::cout;
using std::endl;

void* func(void*);

typedef struct {
    struct sockaddr_in caddr;       // client:ip+port
    int confd;      // server <-socket-> client
}addr;

void* func(void* arg) {
    pthread_detach(pthread_self());
    addr* p = (addr*)arg;
    char buf[100];
    while(1) {
        bzero(buf, 100);
        read(p->confd, buf, 100);
        if (!strncmp(buf, "quit", 4)) break;
        printf("[%s][%d]:%s\n", inet_ntoa(p->caddr.sin_addr),ntohs(p->caddr.sin_port), buf);
    }
    close(p->confd);
    printf("[%s][%d]client exit\n", inet_ntoa(p->caddr.sin_addr), ntohs(p->caddr.sin_port));
    return 0;
}
int main(void) {
    int lfd, cfd;

    lfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr, client_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    bind(lfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(lfd, 8);
    socklen_t client_addr_len;
    client_addr_len = sizeof(client_addr);
    while (1) {
        cfd = accept(lfd, (struct sockaddr*)&client_addr, &client_addr_len);
        if (cfd == -1) {
            perror("accept failed"); continue;
        }
        addr addr1;
        addr1.caddr = client_addr;
        addr1.confd = cfd;
        pthread_t thread;
        printf("[%s][%d]server<--->client--success\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        pthread_create(&thread, NULL, func, (void*)&addr1);
    }
    return 0;
}

冲啊!