linux socket编程实例

本文介绍了Linux下利用Socket进行局域网通信的基本过程,包括服务端的socket创建、监听、接受连接,以及客户端的连接步骤。详细展示了从基本的半双工聊天到实现双向异步聊天的源码,涵盖了TCP服务端和客户端的多线程处理,以及如何通过select函数处理多个客户端连接。内容还包括了无限个客户端聊天的实现和多线程在Socket编程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读目录

  •   基本的局域网聊天
  •   客户端服务端双向异步聊天源码
  •   局域网内服务端和有限个客户端聊天源码
  •   完美异步聊天服务端和客户端源码
  •   C++定时器
  •   select异步代码
  •   pthead多线程

服务端:   服务器端先初始化socket,然后与端口绑定,对端口进行监听,调用accept阻塞,等待客户端连接。   socket() -> bind() -> listen() -> accept() 客户端:   客户端先初始化socket,然后与服务端连接,服务端监听成功则连接建立完成   socket() -> connect()

socket的大概过程是这样的:

  服务端先创建一个套接字,端口绑定,对端口进行监听,调用accpet阻塞,等待客户端连接。客户端创建一个套接字,然后通过三次握手完成tcp连接后服务端accpet返回重新建立一个套接字代表返回客户端的tcp连接,(在accpet成功返回前有一个要注意的是server会有两个队列,一个存放完成三次握手的一个是未完成三次握手的,每次accpet会从完成三次握手的队列中取出一个并一直建立TCP连接,此时才能算是真正的连接成功),完成上面的步骤后即可以开始数据的传输了,数据传输结束后再调用close关闭连接

  此外再说一下select函数在server和client双向通信中的重要作用:网络编程的过程中,经常会遇到许多阻塞的函数,网络编程时使用的recv, recvfrom、connect函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在这里,无法执行下面的代码。selcet函数是一个轮循函数,即当循环询问文件节点,可设置超时时间,超时时间到了就跳过代码继续往下执行,就像我们下面的第一个程序一样,如果不注释掉server的send那么如果server不想client发送消息则进程就会停顿在此处等待server发送无法执行下面的代码,无法接受client发送过来的消息,第二个程序就对此进行的改进,在程序中引入了select当超时后就会跳过当前代码,执行下一步不会一直阻塞。(poll和epoll是对select的改进)

TCP编程的服务器端一般步骤是: UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();   2、设置socket属性,用函数setsockopt(); * 可选 3、绑定IP地址、端口等信息到socket上,用函数bind();  4、开启监听,用函数listen();   5、接收客户端上来的连接,用函数accept();6、收发数据,用函数send()和recv(),或者read()和write();   7、关闭网络连接;   8、关闭监听; 1、创建一个socket,用函数socket();  2、设置socket属性,用函数setsockopt();* 可选   3、绑定IP地址、端口等信息到socket上,用函数bind();4、循环接收数据,用函数recvfrom(); 5、关闭网络连接;
TCP编程的客户端一般步骤是: UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();   2、设置socket属性,用函数setsockopt();* 可选   3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选   4、设置要连接的对方的IP地址和端口等属性;   5、连接服务器,用函数connect(); 6、收发数据,用函数send()和recv(),或者read()和write();   7、关闭网络连接; 1、创建一个socket,用函数socket();   2、设置socket属性,用函数setsockopt();* 可选   3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选   4、设置对方的IP地址和端口等属性; 5、发送数据,用函数sendto();   6、关闭网络连接;

基本的局域网聊天

局域网TCP服务端:

实现的功能是client到server的半双工通信,server只能接受接收client发送过来的消息,但是不能向client发送消息。

#include <sys/types.h>``#include <sys/socket.h>``#include <stdio.h>``#include <netinet/in.h>``#include <arpa/inet.h>``#include <unistd.h>``#include <string.h>``#include <stdlib.h>``#include <fcntl.h>``#include <sys/shm.h>``#include <thread>``#include <iostream>``#define PORT 7000``#define QUEUE 20//连接请求队列``int` `conn;``void` `thread_task()``{``}` `int` `main()``{``  ``//printf("%d\n",AF_INET);//IPv4协议``  ``printf``(``"%d\n"``,SOCK_STREAM);``//字节流套接字``  ``int` `ss = socket(AF_INET, SOCK_STREAM, 0);``//若成功则返回一个sockfd(套接字描述符)``  ``//printf("%d\n",ss);``  ``struct` `sockaddr_in server_sockaddr;``//一般是储存地址和端口的。用于信息的显示及存储使用``  ``/*设置 sockaddr_in 结构体中相关参数*/``  ``server_sockaddr.sin_family = AF_INET;``  ``server_sockaddr.sin_port = htons(PORT);``//将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian) ``  ``//printf("%d\n",INADDR_ANY);``  ``//INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。``  ``//一般来说,在各个系统中均定义成为0值。``  ``server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);``//将主机的无符号长整形数转换成网络字节顺序。 ``  ``if``(bind(ss, (``struct` `sockaddr* ) &server_sockaddr, ``sizeof``(server_sockaddr))==-1)``  ``{``    ``perror``(``"bind"``);``    ``exit``(1);``  ``}``  ``if``(listen(ss, QUEUE) == -1)``  ``{``    ``perror``(``"listen"``);``    ``exit``(1);``  ``}` `  ``struct` `sockaddr_in client_addr;``  ``socklen_t length = ``sizeof``(client_addr);``  ``///成功返回非负描述字,出错返回-1``  ``conn = accept(ss, (``struct` `sockaddr*)&client_addr, &length);``  ``//如果accpet成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。``  ``//accpet之后就会用新的套接字conn``  ``if``( conn < 0 )``  ``{``    ``perror``(``"connect"``);``    ``exit``(1);``  ``}` `  ``char` `buffer[1024];``  ``//创建另外一个线程``  ``//std::thread t(thread_task);``  ``//t.join();``  ``//char buf[1024];``  ``//主线程``  ``while``(1)``  ``{``  ``//这里把send注释掉了,所以这个程序中server只能是接收client端的数据并能给client发送数据,即使不注释掉也没用,因为没有对是否有数据传入和传入``     ``//进行判断所以按照下面的代码这样写,每次都要先让server输入后才能输出client传过来的数据,若是server不输入则程序无法向下走就没有client发送过来的输出,``     ``//而且每次显示也只能是一行,这样显示就全是错的了,所以就需要select和FD_ISSET的判断了``    ``// memset(buf, 0 ,sizeof(buf));``    ``// if(fgets(buf, sizeof(buf),stdin) != NULL) {``    ``//   send(conn, buf, sizeof(buf), 0);  ``    ``// }` `    ``memset``(buffer, 0 ,``sizeof``(buffer));``    ``int` `len = recv(conn, buffer, ``sizeof``(buffer), 0);``//从TCP连接的另一端接收数据。``    ``/*该函数的第一个参数指定接收端套接字描述符;``    ``第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;``    ``第三个参数指明buf的长度;``    ``第四个参数一般置0*/``    ``if``(``strcmp``(buffer, ``"exit\n"``) == 0)``//如果没有收到TCP另一端发来的数据则跳出循环不输出``    ``{``      ``break``;``    ``}``    ``printf``(``"%s"``, buffer);``//如果有收到数据则输出数据``    ``//必须要有返回数据, 这样才算一个完整的请求``    ``send(conn, buffer, len , 0);``//向TCP连接的另一端发送数据。``  ``}``  ``close(conn);``//因为accpet函数连接成功后还会生成一个新的套接字描述符,结束后也需要关闭``  ``close(ss);``//关闭socket套接字描述符``  ``return` `0;``}

  

  

局域网TCP客户端:

/*局域网TCP客户端*/``#include <sys/types.h>``#include <sys/socket.h>``#include <stdio.h>``#include <netinet/in.h>``#include <arpa/inet.h>``#include <unistd.h>``#include <string.h>``#include <stdlib.h>``#include <fcntl.h>``#include <sys/shm.h>` `#define MYPORT 7000``#define BUFFER_SIZE 1024` `int` `main()``{``  ``//
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值