C C++最全Linux下TCP IP编程--TCP实战_linux tcp,2024最新网易C C++面试题目

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

printf("====waiting for client's request=======\n");
//accept 和recv,注意接收字符串添加结束符'\0'
while(1)
{

    if( (connfd = accept(listenfd, (struct sockaddr \*)NULL, NULL))  == -1) {
        printf(" accpt socket error: %s (errno :%d)\n",strerror(errno),errno);
        return 0;
    }
    n = recv(connfd,buff,MAXLINE,0);
    buff[n] = '\0';
    printf("recv msg from client:%s\n",buff);
    close(connfd);
}
close(listenfd);
return 0;

}


**客户端**:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define MAXLINE 4096

int main(int argc, char**argv)
{
int sockfd,n;
char recvline[4096],sendline[4096];
struct sockaddr_in servaddr;

if(argc !=2)
{
    printf("usage: ./client <ipaddress>\n");
    return 0;
}
//创建socket
if( (sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) {
    printf(" create socket error: %s (errno :%d)\n",strerror(errno),errno);
    return 0;
}

memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
//IP地址从“点分十进制”转换到“二进制整肃”
if( inet\_pton(AF_INET,argv[1], &servaddr.sin_addr) <=0 ) {
    printf("inet\_pton error for %s\n",argv[1]);
    return 0;
}
//连接
if( connect(sockfd,(struct sockaddr\*)&servaddr,sizeof(servaddr)) <0) {
    printf(" connect socket error: %s(errno :%d)\n",strerror(errno),errno);
    return 0;
}

printf("send msg to server:\n");
fgets(sendline,4096,stdin);
//send发送
if ( send(sockfd,sendline,strlen(sendline),0) <0) {
    printf("send msg error: %s(errno :%d)\n",strerror(errno),errno);
    return 0;
}

close(sockfd);
return 0;

}


**运行**:  
 g++ server.cpp -o server  
 g++ client.cpp -o client  
 分别打开两个终端窗口  
 一个执行./server命令,  
 ![这里写图片描述](//img-blog.csdn.net/20180316155143176?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L3UwMTM0NTcxNjc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)  
 一个执行./client 1227.0.0.1命令。  
 ![这里写图片描述](//img-blog.csdn.net/20180316155151362?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L3UwMTM0NTcxNjc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)


##### 三、错误记录


在调试过程中发现错误:



socket error: Socket operation on non-socket(errno :88)


经过仔细分析发现:  
 if( `(`sockfd = socket(AF\_INET,SOCK\_STREAM,0)`)`== -1)  
 是优先级出现了问题,这里必须先复制,之后进行关系运算符的比较。  
 本文风格的代码非常容易在这里犯错误,特此记录。


##### 四、多线程并发服务器



> 
> 2018年11月3日补充
> 
> 
> 


多线程和多进程的处理方式类似,都是创建一个新的线程,客户端有请求时,用新创建的线程处理。  
 这里参考文章:[多线程服务器](https://blog.csdn.net/taiyang1987912/article/details/49562909),对代码进行模块化封装。  
 和上文相比,将客户端修改为循环发送,直至输入`q`退出  
 犯的一个错误是服务器printf打印忘记加`\n`,导致没有刷新缓冲区,只有客户端每次端开链接时才打印,汗~



//使用pthread线程库
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#define PORT 6666 //服务器端口
#define BACKLOG 5 //listen队列等待的连接数
#define MAXDATASIZE 1024 //缓冲区大小

void process_cli(int connectfd, struct sockaddr_in client); //客户端请求处理函数
void* start_routine(void* arg); //线程函数

typedef struct _ARG {
int connfd;
struct sockaddr_in client;
}ARG; //客户端结构体

void sys_err(const char * ptr_err)
{
perror(ptr_err);
exit(EXIT_FAILURE);
}

//处理客户端链接的接收工作*
void accept_conn(int listenfd)
{
int connectfd; //socket描述符
pthread_t connectthread; //线程体变量
ARG *arg; //客户端结构体变量
struct sockaddr_in client; //客户端地址信息结构体
int sin_size = sizeof(struct sockaddr_in);

 while(1) {
    //调用accept,返回与服务器连接的客户端描述符
    if ((connectfd = accept(listenfd,(struct sockaddr \*)&client,(socklen_t \*)&sin_size))==-1) {                    
        sys\_err("accept() error\n");
    }
    
    arg = new  ARG;
    arg->connfd = connectfd;
    memcpy(&arg->client, &client, sizeof(client));
    
	//创建线程,以客户端连接为参数,start\_routine为线程执行函数
    if (pthread\_create(&connectthread, NULL, start_routine, (void\*)arg)) {        
        sys\_err("Pthread\_create() error");
    }
}

}

void tcp_server(uint16_t port)
{
int listenfd; //socket描述符
struct sockaddr_in server; //服务器地址信息结构体

//调用socket,创建监听客户端的socket
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 
    sys\_err("Creating socket failed.");
}

//设置socket属性,端口可以重用
int opt = SO_REUSEADDR;        
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    

//初始化服务器地址结构体
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);

//调用bind,绑定地址和端口
if (bind(listenfd, (struct sockaddr \*)&server, sizeof(struct sockaddr)) == -1) {   
    sys\_err("Bind error.");
}   

//调用listen,开始监听
if(listen(listenfd,BACKLOG) == -1){      
    sys\_err("listen() error\n");
}

//处理客户端链接的接收工作
accept\_conn(listenfd);

//关闭监听socket
close(listenfd);        

}
int main()
{

uint16\_t port  = 6666;
tcp\_server(port);

}

void process_cli(int connectfd, sockaddr_in client)
{
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

printf("You got a connection from %s. \n",inet\_ntoa(client.sin_addr) );
//MSG\_WAITALL 
while ((num = recv(connectfd, recvbuf, MAXDATASIZE,0)) > 0) {
	recvbuf[num] = '\0';
    printf("Received size( %d ) message: %s\n",num, recvbuf);	
}

/\* 

num = recv(connectfd, cli_name, MAXDATASIZE,0);
if (num == 0) {
close(connectfd);

return;
}
cli_name[num - 1] = ‘\0’;
printf(“Client’s content is: %s\n”,cli_name);
while (num = recv(connectfd, recvbuf, MAXDATASIZE,0)) {
recvbuf[num] = ‘\0’;
printf(“Received client( %s ) message: %s”,cli_name, recvbuf);
for (int i = 0; i < num - 1; i++) {
sendbuf[i] = recvbuf[num - i -2];
}
sendbuf[num - 1] = ‘\0’;
send(connectfd,sendbuf,strlen(sendbuf),0);
}

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

外链图片转存中…(img-godkO2Vt-1715694740490)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值