1.查看while源代码
系统调用
socket
函数原型
int socket(int domain, int type, int protocol);
参数说明:
domain:指定通信协议族。常用的协议族有AF_INET、AF_UNIX等,对于TCP协议,该字段应为AF_INET(ipv4)或AF_INET6(ipv6)。
type:指定socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM等。SOCK_STREAM针对于面向连接的TCP服务应用。SOCK_DGRAM对应于无连接的UDP服务应用。
protocol:指定socket所使用的协议,一般我们平常都指定为0,使用type中的默认协议。严格意义上,IPPROTO_TCP(值为6)代表TCP协议。
bind
函数原型
int bind(int sockfd,const struct sockaddr * addr,socklen_t addrlen);
bind()函数用于服务器端,服务器的网络地址和端口号通常固定不变,客户端得知服务器的地址和端口号以后,可以主动向服务器请求连接。因此服务器需要调用bind()绑定地址。bingd()函数定义在sys/socket.h头文件中;
sockfd表示socket文件的文件描述符,一般为socket函数的返回值;
listen
函数原型
int listen(int sockfd, int backlog);
参数说明:
sockfd:套接字的文件描述符,即socket()系统调用返回的fd
backlog:保存客户端请求的队列长度
listen()系统调用是比较简单的,但是涉及了backlog,这个参数是比较复杂的,影响到半连接队列和全连接队列
accept
函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:套接字的文件描述符,socket()系统调用返回的文件描述符fd
addr:指向存放地址信息的结构体的首地址
addrlen:存放地址信息的结构体的大小,其实也就是sizof(struct sockaddr)
可以看出,bind(),connect(),以及accept()的参数都是一致的。
connect
函数原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:套接字的文件描述符,socket()系统调用返回的fd
addr:指向存放地址信息的结构体的首地址
addrlen:存放地址信息的结构体的大小,其实也就是sizof(struct sockaddr)
编译并在ubuntu下运行
编译
gcc -o server-while-tcp.out server-while-tcp.c
gcc -o client.out client.c
运行
./server-while-tcp.out
./client.out 192.168.1.***
修改服务器为多线程模式
server.cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<pthread.h>
#include<unistd.h>
#include<arpa/inet.h>
using namespace std;
const int BUF_SIZE=100;
const int MAX_CLIENT=256;
int clientCnt;
int clientSocks[MAX_CLIENT];
pthread_mutex_t mutex;
void* handleClient(void *arg);
void sendMsg(char *msg,int len);
void errorHandling(char *msg);
int main()
{
int serverSock,clientSock,port;
sockaddr_in serverAddr,clientAddr;
pthread_t id;
socklen_t clientAddrSize;
cout<<"Input port:";
cin>>port;
pthread_mutex_init(&mutex,NULL);
serverSock=socket(PF_INET,SOCK_STREAM,0);
memset(&serverAddr,0,sizeof(serverAddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
serverAddr.sin_port=htons(port);
if(bind(serverSock,(sockaddr *)&serverAddr,sizeof(serverAddr))==-1)
errorHandling("bind() error!");
if(listen(serverSock,5)==-1) errorHandling("listen() error!");
while(1)
{
clientAddrSize=sizeof(clientAddr);
clientSock=accept(serverSock,(sockaddr *)&clientAddr,&clientAddrSize);
pthread_mutex_lock(&mutex);
clientSocks[clientCnt++]=clientSock;
pthread_mutex_unlock(&mutex);
pthread_create(&id,NULL,handleClient,static_cast<void *>(&clientSock));
pthread_detach(id); //该函数的功能和pthread_join一样,但不会进入阻塞状态。
cout<<"Connected client IP:"<<inet_ntoa(clientAddr.sin_addr)<<endl;
}
close(serverSock);
return 0;
}
void errorHandling(char *msg)
{
cerr<<msg<<endl;
exit(1);
}
void* handleClient(void *arg)
{
int clientSock(*(static_cast<int *>(arg))),len;
char msg[BUF_SIZE];
while((len=read(clientSock,msg,sizeof(msg)))!=0)
sendMsg(msg,len);
pthread_mutex_lock(&mutex); //删除断开连接的客户端对应的套接字
for(int i=0;i<clientCnt;i++)
{
if(clientSock==clientSocks[i])
{
for(int j=i;j<=clientCnt-2;j++)
clientSocks[j]=clientSocks[j+1];
break;
}
}
clientCnt--;
pthread_mutex_unlock(&mutex);
close(clientSock);
return NULL;
}
void sendMsg(char *msg,int len) //将任何一个客户端发来的消息一一发送给全部客户端
{
pthread_mutex_lock(&mutex);
for(int i=0;i<clientCnt;i++)
write(clientSocks[i],msg,len);
pthread_mutex_unlock(&mutex);
}
client.cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<pthread.h>
#include<unistd.h>
#include<arpa/inet.h>
using namespace std;
const int BUF_SIZE=100;
char name[BUF_SIZE],buf[BUF_SIZE];
void* sendMsg(void *arg);
void* recvMsg(void *arg);
void errorHandling(char *msg);
int main()
{
int sock,port;
sockaddr_in serverAddr;
pthread_t sendThread,recvThread;
void *threadReturn;
char ip[BUF_SIZE];
cout<<"Input ip:";
cin>>ip;
cout<<"Input port:";
cin>>port;
cout<<"Input name:";
cin>>name;
sock=socket(PF_INET,SOCK_STREAM,0);
memset(&serverAddr,sizeof(serverAddr),0);
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.s_addr=inet_addr(ip);
serverAddr.sin_port=htons(port);
if(connect(sock,(sockaddr *)&serverAddr,sizeof(serverAddr))==-1)
errorHandling("connect() error!");
pthread_create(&sendThread,NULL,sendMsg,static_cast<void *>(&sock));
pthread_create(&recvThread,NULL,recvMsg,static_cast<void *>(&sock));
pthread_join(sendThread,&threadReturn);
pthread_join(recvThread,&threadReturn);
close(sock);
return 0;
}
void errorHandling(char *msg)
{
cerr<<msg<<endl;
exit(1);
}
void* sendMsg(void *arg)
{
int sock(*(static_cast<int *>(arg)));
char input[BUF_SIZE];
while(1)
{
cin>>input;
if(!strcmp(input,"q")||!strcmp(input,"Q"))
{
close(sock);
exit(0);
}
strcpy(buf,name);
strcat(buf,":");
strcat(buf,input);
write(sock,buf,strlen(buf));
}
return NULL;
}
void* recvMsg(void *arg)
{
int sock(*(static_cast<int *>(arg)));
char output[BUF_SIZE];
while(1)
{
int len(read(sock,output,BUF_SIZE-1));
if(len==-1) return (void *)-1;
output[len]=0;
cout<<output<<endl;
}
return NULL;
}
编译并在ubuntu下运行
gcc -o srv srv.c
gcc -o cli cli.c
运行
./srv
./cli 192.168.1.***
echo sever
- 服务端改进
-
/* 在客户端发送数据后面加上 */ iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0); if (iRecvLen <= 0) { close(iSocketClient); return -1; } else { ucRecvBuf[iRecvLen] = '\0'; printf("Feedback:%s\n", ucRecvBuf); }
/* 在服务端打印数据后面加上 */ iRecvLen = send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0); if(iRecvLen <= 0) { close(iSocketClient); return -1; }
echo大写
/* 一个完整字符串大写转换函数 */ #include<stdio.h> int main() { char ch[100]; int i; while(scanf("%c",&ch[i])!=EOF) { if(ch[i]>='a'&&ch[i]<='z') ch[i]=ch[i]-32; printf("%c",ch[i]); } return 0; } /* 修改为我们使用的函数 */ int charup(unsigned char ch[1000]); //声明 charup(ucRecvBuf); //调用 int charup(unsigned char ch[1000]) { int i = 0; while (ch[i] != '\0') { if(ch[i]>='a'&&ch[i]<='z') ch[i]=ch[i]-32; i ++; } return 0; }
引用