22061
一、本周的学习感受
首先,本周因为换了一个新的讲师,对我来说又要适应新讲师的讲课速度,风格和习惯,但是我认为新讲师的讲课风格还是挺对我胃口的,我接受的比较快;
本周学习的内容是网络编程的基础。虽然说是基础,但对于第一次接触的我来说,想要学会,依旧是一项不小的挑战,另外还需要结合前面所学习的知识,难度也是直线型上升,但这也是对前面所学的一种复习和巩固。
二、我所遇到的问题和解决的方法
传输多个参数
在写多进程多线程tcp服务端时,写出来的程序只有在连接端口时看到IP和port号,看不出发送者的IP和port号,意思是只能知道谁连接了,但不是不知道谁发送了消息。
所以我想到了在接收程序上发送者的IP地址和port号;在多进程tcp服务端,只需要多传入cli的地址就行,因为子进程可以传入多个参数;但是在多线程只能传入一个参数,就不得不使用结构体函数;
但是我对线程传入结构体参数并不是很熟练,尝试了很多次,终于在不断的试错中完成了此程序;其中最让人难以捉摸的错误是:编译没有问题,但是一连接,出来显示连接成功以外,还会显示“Bad file descriptor”
反复调试后,则显示“Socket operation on non-socket”
真是让初学者非常焦躁。后来想到可能是监听在不断的循环中达到上限,或者是反反复复的强转,让文件符号出现错误;
总而言之,在我的尝试下还是取得了成功。这就是所谓的要理论结合实践吧。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
struct cv{
int cd;
struct sockaddr_in ci;
};
void *rs(void *arg)
{
struct cv *g = (struct cv *)arg;
int cfd = g->cd;
struct sockaddr_in cli = g->ci;
ssize_t recv_bytes,send_bytes;
char buf[128] = {0};
while(1)
{ memset(buf,0,sizeof(buf));
recv_bytes = recv(cfd,buf,sizeof(buf),0);
if(recv_bytes == -1)
{ perror("cuowu4");
break; }
else if (recv_bytes == 0)
break;
printf("(%s|%d): %s\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port),buf);
send_bytes = send(cfd,buf,recv_bytes,0);
if(send_bytes == -1)
{ perror("cuowu5");
break; } }
close(cfd);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
if(argc < 3)
{ perror("cuowu0");
return -1; }
int sfd,ret,cfd,ff;
pthread_t tid;
struct sockaddr_in src,cli;
sfd = socket(AF_INET,SOCK_STREAM,0);
socklen_t len = sizeof(src);
socklen_t addrlen = sizeof(cli);
if(sfd == -1)
{ perror("cuowu1");
return -1; }
src.sin_family = AF_INET;
src.sin_port = htons(atoi(argv[2]));
src.sin_addr.s_addr = inet_addr(argv[1]);
bind(sfd,(const struct sockaddr *)&src,len);
ret = listen(sfd,1024);
if(ret == -1)
{ perror("cuowu2");
return -1; }
while(1){
cfd = accept(sfd,(struct sockaddr *)&cli,&addrlen);
if(cfd == -1)
{ perror("cuowu3");
return -1; }
struct cv *p = (struct cv*)malloc(sizeof(struct cv));
p->cd = cfd;
p->ci = cli;
printf("(%s|%d): 连接成功\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
ff = pthread_create(&tid,NULL,rs,(void*)p);
if (ff != 0)
{ errno = ff;
perror("cuowu6");
return -1; }
pthread_detach(tid); }
return 0;
}
学习成果
对于这一周的学习,我认为还是有一点成果的。不仅了解了许多网络相关的知识点,比如:
生活中关于网络的硬件,像是网卡,路由器,交换机之类的;什么是局域网和广域网;IP,端口号,子网掩码,网管,DNS,DHCP和它们直接的转换关系;网络通讯的原理,路由器和交换机的原理,OSI模型,包括物理层,数据链路层,网络层,传输层,会话层,表示层和应用层;
然后最主要的就是了解了udp服务器和客户端,tcp服务器和客户端的原理,及其一些编程;
udp相比较于tcp,是不可靠的,但是速度较快;tcp服务端于客户端在建立连接是要握手三次,断开时还需要挥手四次,确保数据无丢失和失序,这就是其可靠性;
设计的流程都是先建立socket,在绑定IP地址和端口号,tcp多一步建立监听队列,然后再是数据的接收和发送。
最后学到了多进程多线程的并发服务器,虽然说比之前难上一些,但是却可以让我重温之前学到的许多知识,必然是一种磨炼。
可以说这一周我的学习收货还是很多的,学习必然是会有收货的,因为每个人自然都不会嫌自己的知识储备量太多。