TCP通信是最常见的传输层网络通信协议,在Linux系统中非常常见,建立TCP通信的基础是传输层以下的网络层,即IP协议,而要建立TCP连接,则需要设置两个设备的IP地址,以及在服务器端设备开启通信端口。端口号分为三类,0~1023之间的为公认端口(Well Known Ports),这些端口由 IANA 分配管理。IANA 把这些端口分配给最重要的一些应用程序,让所有的用户都知道,当一种新的应用程序出现后,IANA必须为它指派一个公认端口;用户可以自由使用的注册端口1024-49151,在大多数情况下,这些应用软件和普通程序一样可以被非特权用户打开;客户端使用的端口号49152~65535.这类端口号仅在客户进程运行时才动态选择,因此又叫做短暂端口号。被保留给客户端进程选择暂时使用的。也可以理解为,客户端启动的时候操作系统随机分配一个端口用来和服务器通信,客户端进程关闭下次打开时,又重新分配一个新的端口以最常见的SSH登录为例,主机(开发板)和从机(电脑)的IP地址必须设置为同一网段,主机服务器端口需设置为22。在本帖中,我个人使用的TCP通信端口号为8086,比较好记。
要使用TCP通信的相关函数,需要
#include #include #include #include tinet/in.h>
复制代码
五个头文件;
要使用多线程相关函数,需要
这一个头文件。为什么要在有TCP通信的程序中使用多线程功能呢?因为常规的、不带中断服务机制的TCP通信程序中,接收线程是阻塞的,如果要让服务器在轮询接收客户端发来信息的同时还能处理其它任务,就需要多开一个线程给其它任务,或者把TCP轮询接收放到一个新开辟的线程中。当然,我们也可以启用TCP中断服务,不过程序实现起来比较复杂,而使用多线程解决TCP接收阻塞问题则较为简单。多线程启用的函数,需要在主线程里面添加:
- pthread_create(&id1,NULL,Thread_Show_CurSor,NULL);
复制代码
其中第二个变量就是多线程函数的名称。
- void *Thread_Show_CurSor(void *arg)
{
while(1)
{
LCD_Show_ASCII_64(length*32,locate_over,0xffffffff,0,'_');
LCD_Effect();
usleep(100*1000);
LCD_Show_ASCII_64(length*32,locate_over,0xffffffff,0,' ');
复制代码
要开启Linux TCP通信,我们需要两个结构体,六个函数:
- struct sockaddr_in sockaddr_in_comm,sockaddr_in_settings;
复制代码
sockaddr_in_comm的用于通信的结构体,sockaddr_in_settings是用于初始化设置的结构体。
fd_socket=socket(AF_INET,SOCK_STREAM,0);
if(fd_socket==-1) { printf("套接字初始化失败!n"); return -1; } ret=bind(fd_socket,(struct sockaddr *)&sockaddr_in_settings,addrsize); if(ret==-1) { printf("套接字绑定失败!n"); return -1; } ret=listen(fd_socket,5); if(ret==-1) { printf("服务器监听失败!n"); return -1; } newsock=accept(fd_socket,(struct sockaddr *)&sockaddr_in_comm,&addrsize); if(newsock==-1) { printf("服务器接听失败!n"); return -1; }
recv(newsock,recvbuf,100,0); //接收数据 send(newsock,s,len,0); //发送数据
复制代码
值得注意的是,(一)刚刚上文提到的TCP通信阻塞轮询的特点,阻塞的函数正是recv(),如果某个线程运行到了此函数,则除非TCP另一端有数据发过来,该线程将会一直卡死在此处。(二)TCP通信中,传输层通信用的数据格式为char*字符串,字符串最后一定会有' |