【日常积累】实验室作业Socket实现多个客户端相互通信。

这篇博客介绍了Linux网络编程的基础,包括socket、bind、connect、listen、accept等函数的使用,以及多线程在服务端的应用。通过示例代码展示了如何创建线程接收客户端连接,并处理消息转发。同时,解释了线程状态和资源管理,特别是unjoinable线程的创建和资源释放。此外,还给出了服务端和客户端的简单代码实现。

声明

这是本菜鸡的笔记总结,可能会有一些自己的主观。如有错误还请指正。

所用的函数

  1. socket()
    功 能:创建套接字
    原 型: int socket(int domain, int type, int protocol);
    参 数:
    domain:协议族,通常为 AF_INET,表示 TCP/IP 协议
    type: socket 类型,如: SOCK_STREAM(指 TCP)和
    SOCK_DGRAM(指 UDP)等等
    protocol:套接口所用的协议,一般为 0
    返回值:
    成功: socket 文件描述符
    失败: -1,并设置 errno
  2. bind()
    功 能:将套接字和指定的端口相连
    原 型: int bind(int sock_fd, struct sockaddr_in *my_addr, int addrlen);
    参 数:sock_fd: socket 文件描述符
    my_addr:设置服务器信息的 sockaddr_in 结构体指针
    addrlen: sockaddr_in 结构体的长度
    返回值:
    成功: 0
    失败: -1,并设置 errno
    说 明:
    struct sockaddr_in{
    short int sin_family; //网络通信网络层协议
    AF_INET
    unsigned short int sin_port; //端口
    struct in_addr sin_addr; //IP 地址
    unsigned char sin_zero[8]; //让 sockaddr 与
    sockaddr_in 两个数据结构保持大小相同而保留的空字节
    };
  3. connect()
    功 能:连接服务器请求(客户端使用)
    原 型: int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
    参 数:
    sock_fd: socket 文件描述符
    serv_addr:包含远端主机 IP 地址和端口号的指针
    addrlen: sockaddr_in 结构体的长度
    返回值:
    成功: 0
    失败: -1,并设置 errno
  4. listen()
    功 能:创建一个套接口并监听申请的连接
    原 型: int listen(int sock_fd, int backlog);
    参 数:
    sock_fd: socket 文件描述符
    backlog:请求队列中允许的最大请求数
    返回值:
    成功: 0
    失败: -1,并设置 errno
  5. accecpt()
    功 能:接受客户端的服务请求
    原 型: int accept(int sock_fd, struct sockadd_in* addr, int addrlen);
    参 数:
    sock_fd:被监听的 socket 文件描述符
    addr:包含客户端 IP 地址和端口号的指针
    addrlen: sockaddr_in 结构体的长度返回值:
    成功:客户端套接字描述符
    失败: -1,并设置 errno
  6. write()
    功 能:写入数据到 fd 中
    原 型: ssize_t write(int fd,const void *buf,size_t nbytes);
    参 数:
    fd: socket 文件描述符
    buf:字符串数据地址
    nbytes:字符串数据大小
    返回值:
    实际写入的字节数,小于 0 为写入错误
    6、 read()
    功 能:从 fd 中读取数据
    原 型: ssize_t read(int fd,void *buf,size_t nbyte)
    参 数:
    fd: socket 文件描述符
    buf:字符串数据地址
    nbyte:字符串数据大小
    返回值:

0: 实际读取的大小
=0:读到末尾了
<0:读取错误
8、 close()
功 能:关闭套接字
原 型: int close(sock_fd);
参 数:
sock_fd:要关闭的 socket 文件描述符
返回值:
成功: 0
失败: -1

进程线程的创建和释放

2.2:线程的创建

pthread_create (thread, attr, start_routine, arg)
thread:进程号(自己定义的)
attr:NULL
start_routine:开启的函数名称(也就是其首地址)
arg :NULL

2.3:资源的释放(在这里我使用的是unjoinable模式)
	pthread_detach(pthread_self());
	这个函数可以使我们的线程在退出时立即释放资源。

pthread有两种状态joinable状态和unjoinable状态,如果线程是joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用了pthread_join之后这些资源才会被释放。若是unjoinable状态的线程,这些资源在线程函数退出时或pthread_exit时自动会被释放。
2.unjoinable属性可以在pthread_create时指定,或在线程创建后在线程中pthread_detach自己(我们这就是这样创建), 如:pthread_detach(pthread_self()),将状态改为unjoinable状态,确保资源的释放。或者将线程置为 joinable,然后适时调用pthread_join.
3.其实简单的说就是在线程函数开始加上 pthread_detach(pthread_self()),线程状态改变,在函数尾部直接调用pthread_exit()线程就会自动退出。

pthread_join()即是子线程合入主线程,主线程阻塞等待子线程结束,然后回收子线程资源。

#头文件解读
3.1:网络编程用的头文件
#include <sys/socket.h>
3.2:线程用的头文件
#include <pthread.h>

特定结构体。

4.1:sockaddr_in为协议族,地址,端口等必要信息构成的结构体,对信息的使用方便很多。

代码

服务器端的
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <unistd.h>

int SERVER_PORT = 8091;

typedef unsigned char u8;
typedef char cmd_key_t;
typedef int mid_t;
#define MESSAGE_LENGTH_MAX  512


typedef struct
{
   
   
	cmd_key_t cmd_key; //
	mid_t own;
	mid_t peer;
	u8 message[MESSAGE_LENGTH_MAX];
} client_message_t;


int Gfd[1024];


int _id2peer_trans_func_(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值