多线程与socket

前言

记录一下ubuntu系统下,多线程与socket通讯的知识。

多线程

一、多线程注意事项

  1. 编译需导入pthread库,加上-lpthread,即

    gcc 文件名 -o 目标文件名 -lpthread
    
  2. 线程中,禁止使用exit函数,会导致进程内所有线程全部退出,应使用

    void pthread_ex it(void *retval);
    

    一般retval=NULL。

二、线程创建

  1. 预留分配线程ID;
    pthread_t tid;

  2. 使用函数

    int pthread_create(
    参数1:传出参数,保存系统为我们分配好的线程ID。pthread_t类型
    参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
    参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。void *类型
    参数4:线程主函数执行期间所使用的参数。传入下面线程体的void *arg)
    
  3. 线程体,本质上是一个函数

    void* thr(void *arg){函数体}
    

三、其他

  1. 输出打印到屏幕,另一种写法:

     fprintf(stderr,"stderr!");
    
  2. 把一个描述性错误消息输出到标准错误 stderr:

     perror("simplex-talk:connect");
    

socket通讯

一、hostent结构体

  1. 来源:
    hostent结构体是gethostbyname的返回值,而gethostbyname(char *host)是用解析域名的函数,其中host为域名,一般由外部给定(可以用主函数参数传入)

  2. 结构:

    struct hostent  
    {  
        char *h_name;         //正式主机名  
        char **h_aliases;     //主机别名  
        int h_addr;       //主机IP地址类型:IPV4-AF_INET  
        int h_length;         //主机IP地址字节长度,对于IPv4是四字节,即32位  
        char **h_addr_list;   //主机的IP地址列表  
    }; 
    

    是结构体,其中变量可以直接访问。

二、sockaddr_in结构体

  1. 初始化:

    struct sockaddr_in sin;
    bzero((char*)&sin,sizeof(sin));	//归零
    sin.sin_family=AF_INET;		//IP地址类型,AF_INET为一个系统预定义的数
    sin.sin_port=htons(23);		//??23为任意指定数
    bcopy(hostent.h_addr,(char*)&sin.sin_addr,hostent.h_length);//或者sin.sin_addr.s_addr= inet_addr("132.241.5.10");
    

    一个sockaddr_in对应一个通讯者,记录通讯者信息(信息来自gethostbyname(IP)的分析结果hostent)

  2. 结构:

    struct sockaddr_in
    {  
    	short int sin_family;	//IP地址类型,=AF_INET即可
    	unsigned short int sin_port; 
    	unsigned char sin_zero[8];
     	struct in_addr sin_addr; 
    }; 
    

    是结构体,其中变量可以直接访问。

三、客户端(发信息)流程

  1. 由IP地址获取通讯者信息,由gethostbyname(IP)分析存入hostent中;

  2. 把分析结果hostent填入sockaddr_in中( 具体要填的见上方sockaddr_in初始化),建立代码层面的通讯者;

  3. 套接字s
    socket()函数来创建套接字s(初始化s):

    int s =socket(PF_INET,SOCK_STREAM,0)
    

    connect()函数来连接s与通讯者sin:

    connect(s,(struct sockaddr*)&sin,sizeof(sin)
    
  4. send就好。

    send(s,字符串,字符串长度(加'\0'),0)
    

四、服务器端(收信息)流程

  1. 以本地地址INADDR_ANY,初始化一个sockaddr_in,记为sin;可用方法:

    sin.sin_addr.s_addr=INADDR_ANY;
    
  2. 套接字s
    socket()函数来创建套接字s(初始化s):

    int s =socket(PF_INET,SOCK_STREAM,0)
    

    bind()函数来绑定s与服务器sin:

    bind(s,(struct sockaddr*)&sin,sizeof(sin)
    
  3. 侦听功能将套接字置于侦听传入连接的状态

    listen(s,MAX_PENDING);
    

    其中MAX_PENDING为一个int,是挂起的连接队列的最大长度;也可写为SOMAXCONN(自动决定)

  4. 循环,尝试接受客户端的请求

    new_s=accept(s,(struct sockaddr*)&sin,&len)
    

    客户端被记录为new_s

  5. 接受客户端new_s的信息

    len = recv(new_s,buf,sizeof(buf),0)
    

    信息记录在字符串buf里,读出来的字节大小为len,读完了客户端阻塞的,当客户端下线,返回0,所以一般这样用

    while (len = recv(new_s,buf,sizeof(buf),0))
    {
        fputs(buf,stdout);
    }
    
  6. 关闭new_s

    close(new_s)
    

五、虚拟机与本机互ping确认IP地址

  1. 利用ipconfig命令在命令行(终端)获取主机和虚拟机的ip信息。

  2. 在主机(windows)找当前连接网络的IPv4(我的是10.130.55.240)

  3. 在虚拟机终端里

    ping 2中查到的对应ip地址
    

    ping通会有返回数据

  4. 在虚拟机运行

    ifconfig -a
    

    找inet(我的是192.168.0.129),可能会报错,一般是没有安装包,安装即可

    sudo apt install net-tools
    
  5. 在主机(windows)命令行,直接ping对应ip即可

六、c语言持续从键盘获取字符串

#define MAX_LINE 256
char buf[MAX_LINE];
while(fgets(buf,sizeof(buf),stdin))
{
    buf[MAX_LINE-1]='\0';
    len =strlen(buf)+1;
}

七、其他

  1. 具体程序请参考这里https://gitee.com/chengyunqi/robot-software-engineering/tree/master/ch2,存在一些循环关系需要注意。
  2. 需要在循环内创建线程,可以通过pthread_kill(tid,0)判断线程是否已经被创建,从而避免重复创建线程。
  3. ubuntu系统下测试程序时,可以分别开两个终端,一个充当客户端,一个充当服务器。
  4. 跨设备进行socket通信时,需要注意防火墙的问题
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值