server端程序
进行测试时:
运行server程序
新开一个终端,输入命令 : nc 127.0.0.1 9527 //端口号为9527
在命令行中输入 abc 即可回传得到大写的ABC
/*server.c */
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<error.h>
#include<pthread.h>
#include<netinet/in.h>
#define SERV_PORT 9527
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main()
{
int sfd = 0,cfd = 0;
int res = 0,i = 0;
char buf[BUFSIZ]; //BUFSIZ大小为8192字节
struct sockaddr_in serv_addr,clit_addr;
socklen_t clit_addr_len;
/*设置 struct sockaddr_in 里面的内容 采用IPv4 端口号为9527 IP号由INADDR_ANY生成的二进制的IP地址 */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*生成套接字,并校验*/
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd == -1){
sys_err("socket error");
}
/*绑定端口号+IP地址 */
bind(sfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
/*设置监听的上限 */
listen(sfd,20);
/*监听,阻塞至有客户端连接,并返回一个新的套接字与客户端建立通讯 */
clit_addr_len = sizeof(clit_addr);
cfd = accept(sfd,(struct sockaddr *)&clit_addr,&clit_addr_len);
if(cfd == -1){
sys_err("accpet error");
}
/*读取客户端发来的信息,并转化为大写 */
while(1){
res = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,res);
for(i = 0;i < res;i++)
buf[i] = toupper(buf[i]);
write(cfd,buf,res);
}
close(sfd);
close(cfd);
return 0;
}
在服务端可以用INADDR_ANY表示本地的IP地址,直到与客户端建立联系时才确定下来真正的IP
如何在服务端把客户端的IP及端口号打印出来
在上面程序的基础上:
将【struct sockaddr_in】结构体里面的clit_addr.sin.port(端口号)和clit_addr.sin_addr.s_addr(网络字节顺序并存储为二进制 的IP地址)打印出来。
其中打印端口号时只要将网络字节顺序转化为本地字节顺序ntohs(clit_addr.sin.port);
打印IP地址时不但要将网络字节顺序转化为本地字节顺序,同时要将二进制转化为点分十进制,所以采用专门的函数inet_ntop()
/*方法一 */
char client_IP[1024];printf("client IP :%s,port :%d",inet_ntop(AF_INET,&clit_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),ntohs(clit_addr.sin_port));
/*方法二 */
printf("\n已连接了客户 : %s:%d \n", inet_ntoa(clit_addr.sin_addr), ntohs(clit_addr.sin_port));
在上述的方法中方法一有时候在Ubuntu中无法实现,在centos中可以实现;
有时候在centos中可以单独实现方法二,不能单独实现方法一;把两种方法同时写在一起的时候能够实现。后发现解决办法:printf()输出缓冲区里面的内容需要达到一定的条件的例如 碰到 \n 会刷新输出,而方法一中没有达到满足要求的情况下是不会输出的,可以在后面加上:fflush(stdout)函数。强制刷新。
扫描二维码关注公众号,回复: 5394519 查看本文章详细请见博客:https://blog.csdn.net/zqixiao_09/article/details/50234733
client端程序
/*client.c */
#include<stdio.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<error.h>
#include<pthread.h>
#include<netinet/in.h>
#define SERVPORT 9527 /*定义服务端的端口号为9527*/
void sys_err(const char *err)
{
perror(err);
exit(1);
}
int main(int argc,int *argv[])
{
struct sockaddr_in server_addr;
int cfd = 0,i=10 ;
char buf[10] = "hello\n";
/*设置服务端的struct sockaddr */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVPORT);
inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);/*将127.0.0.1转换为网络字节序,并转化为二进制,回写给【server_addr.sin_addr.s_addr】*/
/*建立套接字 */
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1){
sys_err("socket error");
}
/*连接服务端,进行connect操作时,系统会隐性地把客户端的IP+PORT生成并绑定 */
int ret = connect(cfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
if(ret == -1)
sys_err("connect error");
while(i--){
/*写给服务端套接字的接受缓冲区 */
write(cfd,"hello\n",6);
/*从服务端套接字的发送缓冲区读取数据,并写在屏幕上 */
ret = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
sleep(1);
}
close(cfd);
return 0;
}
在两个终端中分别运行这两个程序,运行效果如下: